2

嗨,我有这样的类定义

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

我在其他一些类1中这样做

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

现在我在class2做这个

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

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

4

1 回答 1

4

你的问题不是很清楚。

但有人告诉我 ThreadLocals 对于每个线程都是本地的。我在这里看到了一些冲突。

这是对的。没有冲突。与 a 一起存储的值对象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) 时,该值是当时设置的跳过线程局部变量。

为了更具体地回答您的问题,请在此示例中:当 thread1 执行时,class1 和 class2 代码都将被跳过。当由 thread2 执行时,它们不会被跳过。

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

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

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

于 2010-01-29T08:49:47.233 回答