ThreadLocal不安全的情况举例(附代码)

ThreadLocal通过Thread.threadlocals保存ThreadLocal的副本,但是ThreadLocal变量在多线程情况下仍然是不安全的。

 

 

class MyClass{
    private Integer value;
    public MyClass(){
    }
    public MyClass(Integer value){
        this.value=value;
    }

    public Integer getValue() {
        return value;
    }

    public void setValue(Integer value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "MyClass{" +
                "value=" + value +
                '}';
    }
}
public class ThreadLocalTest {
    static ThreadLocal<MyClass> threadLocal=new ThreadLocal<>();

    public static void main(String[] args) {
        MyClass myClass=new MyClass();
        new Thread(){
            @Override
            public void run() {
                myClass.setValue(10);
                threadLocal.set(myClass);
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                myClass.setValue(10); //这个值会影响下面线程最后一次打印
            }
        }.start();


        new Thread(){
            @Override
            public void run() {
                myClass.setValue(20);
                threadLocal.set(myClass);
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentThread().getName()+":"+threadLocal.get());

            }
        }.start();
    }
}

通过查看上面代码的执行结果,可以看到,两个线程对myClass的value设置后,相互影响,线程逻辑完全混乱了,并不是我们想象中的各自拥有变量副本。

 

 

正确的写法是多线程共享ThreadLocal变量,但是不共享ThreadLocal里面的变量。也就是每个线程共享Thread.threadLocals的key,而不不共享Thread.threadLocals的value。

 

public class ThreadLocalTest111 {
    static ThreadLocal<MyClass> threadLocal=new ThreadLocal<>();

    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                MyClass myClass=new MyClass(10);
                threadLocal.set(myClass);
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                myClass.setValue(10); //这个值会影响下面线程最后一次打印
            }
        }.start();


        new Thread(){
            @Override
            public void run() {
                MyClass myClass=new MyClass(20);
                threadLocal.set(myClass);
                System.out.println(currentThread().getName()+":"+threadLocal.get());
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(currentThread().getName()+":"+threadLocal.get());

            }
        }.start();
    }
}

 

上面这个代码就是线程安全了。

 

posted on 2021-04-21 11:25  坚守梦想  阅读(396)  评论(0编辑  收藏  举报