为什么ThreadLocal变量需要静态?

时间:2016-03-03 06:43:52

标签: java multithreading

我已经阅读了很多关于为什么ThreadLocal变量需要是静态的文章(尽管没有必要),但我不知道为什么它应该是静态的。

我已经阅读了here和许多其他链接,但没有明白这一点。

我做过类似的事情

public class ThreadLocalDemo{

    public static void main(String[]args)throws Exception{
        SharedRersource r1= new SharedRersource();
        Thread t1= new Thread(r1);
        Thread t2= new Thread(r1);
        t1.start();
        t2.start();
        t1.join();
        t2.join();
        System.out.println("Main thread Exiting...");
        }

    }

class SharedRersource implements Runnable{


        private ThreadLocal<Integer> threadId = new ThreadLocal(){
            protected Integer initialValue(){
                return (int)(Math.random()*100);
                }
        };
        public void run(){

            try{
                Thread.sleep(2000);
            }
            catch(InterruptedException e){
                e.printStackTrace();
                }
                System.out.println(threadId.get());

            }
        };

此处主题t1和t2拥有threadId的私有副本,而不是为什么它应该是静态的

请更好地了解我。 谢谢

4 个答案:

答案 0 :(得分:6)

这个问题的答案在于ThreadLocal实现。

将ThreadLocal视为容器

ThreadLocal是一个内部ThreadLocalMap 的容器,这个ThreadLocalMap是threadlocal需要静态的关键(尽管不是必需的,但是建议)保持静止)。

因为我们想要 single container per class not container per instance。如果我们每个实例都有容器,那么我们将拥有与实例一样多的容器,这会产生内存泄漏。

这里有更多细节

  1. http://www.0xcafefeed.com/2004/06/of-non-static-threadlocals-and-memory/
  2. https://www.appneta.com/blog/introduction-to-javas-threadlocal-storage/

答案 1 :(得分:2)

根据您的实施,您({逻辑上) 4个不同的实例 threadID

  1. r1.threadID{t1} - 保存在资源r1中并由线程t1观察的实例。如果它将被中断,它将由线程t1打印。

  2. r2.threadID{t2} - 保存在资源r2中并由线程t2观察的实例。如果它将被中断,它将由线程t2打印。

  3. r1.threadID{t2} - 保存在资源r1中并由线程t2观察的实例,例如,如果它(直接)调用r1.run()

  4. r2.threadID{t2} - 保存在资源r2中并由线程t1观察的实例,例如,如果它(直接)调用r2.run()

  5. 您不太可能需要第3和第4个实例,因此您可以:

    • 使变量静态

    在这种情况下,您将拥有两个实例threadID{t1},由线程t1观察到,threadID{t2},线程{{ 1}}。

    • 使变量非ThreadLocal

    在这种情况下,您将拥有两个实例t2,通过r1.threadID(通过主题r1)和t1观察,通过r2.threadID(线程r2)观察到。

答案 2 :(得分:0)

没有固有的原因ThreadLocal变量需要是静态的。就是这样,ThreadLocal解决的问题通常只发生在基于静态设计思想的程序中。

IMO,您最有可能在最初是单线程的代码中找到ThreadLocal,直到有人升级&#34;它使用多个线程。当大量代码最初引用某些 static 变量时,本地线程就派上用场了,现在你需要每个运行在同一代码体中的线程都拥有自己的副本。 / p>

IMO,ThreadLocal是一种代码气味 - 一种不良设计的标志。一个设计良好的多线程程序不应该需要它。

答案 3 :(得分:0)

ThreadLocal不需要static。就像任何其他变量一样,这取决于您的意图:

public class FooClass {
  static Integer staticVar                          // 1 per process
  Integer var;                                      // 1 per instance

  static ThreadLocal<Integer> staticThreadLocalVar; // 1 per thread
  ThreadLocal<Integer> threadLocalVar;              // 1 per thread per instance
}

您提供的报价完全是指上面列出的第三种情况。

  

ThreadLocal 实例通常是类中的私有静态字段   希望将州与线程

相关联

但是,在某些情况下,将状态与每个实例的线程相关联可能是完全合理的,在这种情况下,您可能希望使用non-static ThreadLocal代替(第四种情况)。