代码之家  ›  专栏  ›  技术社区  ›  Ravi Gupta

私有静态最终实例的线程本地行为

  •  2
  • Ravi Gupta  · 技术社区  · 14 年前

    嗨,我有这样的课堂定义

    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
    

    我在别的班级里也这样做

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

    现在我在二班做这个

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

    现在我有点困惑,我知道第一类的事情会发生,因为我设置了 不接受本地线程。我怀疑第二类的事情会不会发生? 我的逻辑是我只有一个JDBCInterceptor实例,所以在所有的interrupt()调用中都应该有相同的状态。但有人告诉我,每个线程的线程局部变量都是本地的。我在这里看到一些冲突。请帮我一下。

    1 回复  |  直到 13 年前
        1
  •  4
  •   Kevin Brock    14 年前

    你的问题不太清楚。

    但有人告诉我,每个线程的线程局部变量都是本地的。我在这里看到一些冲突。

    这是正确的。没有冲突。值对象存储在 ThreadLocal 对每个线程都是唯一的。它实际上与 Thread 对象内部,因此当线程终止时 全部的 线程局部值也会被删除,并可用于垃圾收集,除非有其他线程对它们的引用。

    如果两个类都是用同一线程执行的,那么除非在调用之间更改线程的局部值,否则这两个类的结果都相同。如果一个不同的线程执行Class2,那么这两个线程将具有不同的值(根据您的示例)。

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

    现在,您可以使用 线程本地 初始值设定项,如下所示:

    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)时,这个值就是skip thread局部变量当时设置的值。

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

    注意,有另一种线程本地调用 InheritableThreadLocal . 在我的例子中,这会表现得不同 线程2 会像在 线程1 在该线程启动第二个线程时。

    编辑 如果Class1中的代码总是将Skip值设置为true,那么行为会有所改变。如果线程首先执行Class1,然后执行Class2,则跳过将是 true 两者兼而有之。如果线程首先执行Class2,然后执行Class1,则跳过 false 对于前者和 以后。你不表示有一种方法可以将skip返回到 .

    编辑 重读你的问题。如果您实际上想要对所有线程使用完全相同的状态,那么您将不会使用 线程本地 . 只需使用一个正则变量并将其标记为 volatile 或者用同步保护它。