【问题标题】:Why ThreadLocal variable need to static?为什么 ThreadLocal 变量需要静态?
【发布时间】:2016-03-03 06:43:51
【问题描述】:

我已经阅读了很多关于为什么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 的私有副本,而不是为什么它应该是静态的

请给我一个更好的理解。 谢谢

【问题讨论】:

  • 您链接到的问题的答案很好地解释了它。你不明白什么?您是否了解如果您有 10 个对象,每个对象都有一个 ThreadLocal 实例字段,那么您有 10 个不同的地方可以将某些状态与当前线程相关联?你通常不希望那样。您通常想要的是“当前正在使用此线程的用户是 John”,或“与当前线程关联的事务是那个”。
  • 技术上不一定是这样,但你能说出你不希望它是静态的一件事吗?
  • @Voo :问题是我只是看到 SpringSecurity ContextHolder 类,其中 Authentication 对象保存在 ThreadLocal 变量中。所以要了解我需要了解 ThreadLocal 状态
  • @JBNizet:为什么当每个线程本地副本都是每个线程私有时,我需要 10 个不同的对象
  • 每当我遇到“我为什么需要这个?”问题(例如,每当我想到一个问题时),我发现最好的方法是将知识藏在脑海中,不要想太多。然后,当实际工作中出现这个话题时,我可以将这个想法应用到那个具体的例子中。我查看“最佳实践”的答案,然后提出替代方案——我经常最终意识到为什么最佳实践在那个特定情况下也是最好的。重复几次,然后你就知道为什么这是个好主意了。

标签: java multithreading


【解决方案1】:

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

将 ThreadLocal 视为一个容器

ThreadLocal 是一个在内部维护ThreadLocalMap 的容器,这个ThreadLocalMap 是threadlocal 需要静态的关键(虽然不是必需的,但建议保持静态)。

因为我们想要 single container per classnot 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/

【讨论】:

    【解决方案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()

    您不太可能需要 3-rd 和 4-th 实例,因此您可以:

    • 使变量静态

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

    • 使变量非ThreadLocal

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

    【讨论】:

    • javaworld.com/article/2073352/core-java/simply-singleton.html,这就是你要向我解释的吗?
    • 不,我只是试图通过将 ThreadLocal 变量声明为 非静态 来解释 你有什么。在我的回答中描述的任何情况下,您都有多个threadID 实例,因此它不是单例模式。
    • 在你的回答中 r2 是什么?
    • @Mukeshkumarsaini:糟糕,我错误地阅读了您问题中的代码,因为线程使用了不同的资源。我将重写答案(或者,可能会将其删除为不正确)。
    • 所以,您的代码正确。但是有两个相同线程,从相同的可运行创建的原因是什么? “相同”是指线程无法在外部被其他线程(执行上下文)区分开来。 ThreadLocal 变量只允许从线程本身的上下文中区分线程。
    【解决方案3】:

    ThreadLocal 变量必须是静态的没有固有原因。只不过,ThreadLocal解决的问题,是一个通常只会出现在基于static-y设计思想的程序中的问题。

    IMO,您最有可能在最初是单线程的代码中找到 ThreadLocal,直到有人“升级”它以使用多线程。当大量代码最初引用某个 static 变量时,本地线程会派上用场,而现在您需要运行同一代码体的每个线程都有自己的副本。

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

    【讨论】:

      【解决方案4】:

      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 实例通常是类中的私有 static 字段 希望将状态与线程

      相关联

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

      【讨论】:

        猜你喜欢
        • 2011-02-16
        • 2014-10-28
        • 2020-10-22
        • 2011-09-13
        • 2011-10-21
        • 2021-11-23
        相关资源
        最近更新 更多