繁体   English   中英

ThreadLocal:为什么一个线程所做的更改在另一个线程中可见

[英]ThreadLocal: why changes made by one thread is visible in other thread

考虑以下代码:

public static void main(String args[]) {
        
        
        Set<Integer> set=new HashSet<>();
       set.add(1);
        
        ThreadLocal<Set> var1=new ThreadLocal<>();
        
        //THREAD1
        Runnable r=()->{
                    
            var1.set(set);

            for(int i=1;i<=10;i++)
             System.out.println("Thread ID:"+Thread.currentThread()+":  "+var1.get());
            };

        Thread th=new Thread(r);
        th.start();
        
        //THREAD2
        Thread th1=new Thread(()-> {
                
            var1.set(set);
            
            var1.get().remove(1); //removing 1 from this thread copy of set.
            var1.get().add(2);    //adding 2 to this thread copy of set 
            
            for(int i=1;i<=10;i++)
             System.out.println("Thread ID:"+Thread.currentThread()+":  "+var1.get());
             
        });
        th1.start();
        
        
    }

Output:

Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-0,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]
Thread ID:Thread[Thread-1,5,main]:  [2]

为什么 Thread2 所做的更改(即删除 1 和添加 2)对 thread1 也是可见的? 这里的理想用例是什么?

线程本地不是值的副本(您存储的内容),它更像是变量的副本(您存储它的位置)。 它是一个变量,它(通常)为访问它的每个线程存储不同的值。

虽然ThreadLocal能够在每个线程中引用不同的值,但您已经为两者分配了相同的值。 一个线程中值的突变恰好在另一个线程中可见。 (但是,这并不能保证;这种对HashSet的并发访问可能会导致错误。)

ThreadLocal的一个更有用的应用程序将为每个线程分配不同的值。 在您的示例中,这意味着在Runnable中创建一个HashSet 这保持了每个值与一个线程的隔离,并避免了代码中的并发错误。

我不确定ThreadLocal是否有“理想”用例; 当无法实现理想时,我将其视为解决方法的工具。 我认为它们是必要的邪恶,最后的手段。 但是,例如,当不能作为方法参数传递时,您可以使用ThreadLocal在堆栈上下传递额外数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM