java - 私有(private)静态最终实例的线程本地行为

标签 java thread-local

嗨,我有这样的类定义

public class JdbcInterceptor {
private static final JdbcInterceptor instance = new JdbcInterceptor();
private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>();
     public static JdbcInterceptor getInstance() {
 return instance;
}
public void skipIntercept() {
 dontIntercept.set(true);
}
public boolean interrupt() {
boolean di = dontIntercept.get()!=null?dontIntercept.get().booleanValue():false;
if (di) {
        dontIntercept.set(false);
        }
return di;
}// end interrupt
}// end class

我在其他一些类(class)中这样做

//class1 stuff
JdbcInterceptor.getInstance().skipIntercept();
if(JdbcInterceptor.getInstance().interrupt())
{ // class1 stuff happens
}

现在我在 class2 中执行此操作

//class2 stuff
if(JdbcInterceptor.getInstance().interrupt())
{ // class2 stuff happens
}

现在我有点困惑,我知道 class1 的事情会发生,因为我设置了 不要拦截ThreadLocal。我的疑问是 class2 的事情是否会发生? 我的逻辑是,我只有一个 JdbcInterceptor 实例,因此相同的状态应该在所有中断()调用中可用。但有人告诉我,ThreadLocals 对于每个线程来说都是本地的。我在这里看到一些冲突。请帮我解决这个问题。

最佳答案

你的问题不太清楚。

But I have been told that ThreadLocals are local for each thread. I see some conflict here.

这是正确的。不存在冲突。使用 ThreadLocal 存储的值对象对于每个线程来说都是唯一的。它实际上与 Thread 对象一起存储在内部,因此当线程终止时,所有线程本地值也会被删除并可用于垃圾回收,除非有来自其他线程的其他引用线程。

如果两个类都使用同一个线程执行,那么除非您在调用之间更改本地线程的值,否则它们将具有相同的结果。如果不同的线程执行 class2,那么两者将具有不同的值(根据您的示例)。

您可能会混淆时间和类/方法存储和代码中发生的线程执行。这两者非常不同。一个线程可以执行任何和所有方法,或者可以让多个线程在单个类中执行相同的方法。您无法“看到”代码中的线程。如果没有其他图片,您必须想象它们 - 这确实需要一些仔细的想象。

现在,您可以使用 ThreadLocal 初始值设定项使代码更加清晰,如下所示:

private static ThreadLocal<Boolean> dontIntercept = new ThreadLocal<Boolean>() {

    @Override
    protected Boolean initialValue() {
        return Boolean.FALSE;
    }

};

然后,当您使用本地线程时,您不必检查它是否为null,如下所示:

public boolean interrupt() {
    return dontIntercept.get().booleanValue();
}// end interrupt

这里尝试展示如何使用两个以上线程执行此操作:

 Thread1 start---class1(skip=false)-+-skip(true)---+class1(true)--+class2(true)----+-end
                    |               |              |              |                |
                    Thread2 start---+-class1(false)+--------------+class2(false)---+-class1(false)---end

当我显示 classN(val) 时,该值是当时跳过线程局部变量设置的值。

为了更具体地回答你的问题,在这个例子中:当线程1执行时,class1和class2代码都将被跳过。当由 thread2 执行时,它们不会被跳过。

请注意,还有另一种线程本地称为InheritableThreadLocal。在我的示例中,这会表现得有所不同,因为 Thread2 会继承该线程启动第二个线程时 Thread1 中的值。

编辑 如果 class1 中的代码始终将跳过值设置为 true,则行为会发生一些变化。如果线程首先执行 class1,然后执行 class2,则两者的skip 都将为 true。如果线程先执行 class2,然后执行 class1,则前者的skip将为false,后者的skip将为true。您没有表明有一种方法可以将跳过返回到 false

编辑重读您的问题。如果您实际上希望所有线程具有完全相同的状态,那么您就不会使用 ThreadLocal。只需使用常规变量并将其标记为 volatile 或通过同步保护它。

关于java - 私有(private)静态最终实例的线程本地行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2160601/

相关文章:

基于 Java 的加密器,仅生成字母数字字符

c# - 在主线程中设置线程本地值并在另一个线程中获取

java - AWS中如何隔离环境?

java - 多线程方面比较java和scala

java - 如何在实际遍历所有结果之前获取 App Engine 查询中的结果数

java - 下载图像时 BitmapFactory.decodeStream 返回空值

c++ - 为什么编译器不支持 c++11 thread_local 存储?

c# - CallContext.LogicalGetData() 与 ThreadLocal/ThreadStatic

java - 为不同的 session 获得相同的 Threadlocal

django - Django 持久数据库连接线程安全如何?