ThreadLocal是如何存储数据的?理解源码,规避ThreadLocal坑

通常我们为了规避单例模式下多线程之间共享全局变量的问题,会使用ThreadLocal,不过很多人不知道ThreadLocal里数据的存储方式和我们平时理解的不太一样。

 

源码解析(直奔主题):

每个线程都有一个ThreadLocalMap对象:

 

 

这个Map里存了所有线程变量中保存的数据,保存的方式:

 

以ThreadLocal对象的弱引用作为key,ThreadLocal里“存放”的数据作为value,放在该Map中。

 

 

 

在我们创建了一个线程变量 maxLife=new ThreadLocal<Integer>(),之后执行其set(xxx)方法,其实是以maxLife这个对象为键,以xxx为值,将这组键值对放入当前线程的ThreadLocalMap对象中。

 

这种方式的存储有一个坑必须注意:

1、ThreadLocal对象一旦创建,那么在线程运行过程中不可随意修改其引用,替换会导致之前保存的内容无法找到:

——如果ThreadLocal不是static的,那么线程运行过程中多次修改其引用,可能会导致当前线程之前set的值无法找到;

——如果ThreadLocal是static的或者ThreadLocal持有者对象是单例的(关键在于是否被多个线程共享),那么线程运行过程中多次修改其引用,可能会导致所有共享该变量的线程之前set的值无法找到;

 

我们以static的ThreadLocal变量为例,通过简易代码加深理解

public class CustomThread extends Thread{

    static ThreadLocal<String> threadLocal = null;

    private String key;

    public CustomThread(String key){
        this.key = key;
    }

    public void run() {
        threadLocal = new ThreadLocal<>();
        threadLocal.set(key);
        try {
            Thread.sleep(3000l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(threadLocal.get());

    }

    public static void main(String[] args) {
        CustomThread t1 = new CustomThread("t1");
        CustomThread t2 = new CustomThread("t2");
        t1.start();
        t2.start();
    }
}

多次执行,将看到t1或者t2只能有一个打印出来。另一个永远是null。

maxLife 这个变量由于是static的,在t1和t2中是共享的,虽然maxLife作为key在t1和t2各自的ThreadLocalMap中对应的值是不一样的

我在t1或者t2中替换maxLife的引用,将导致之前set的值无法再次获取,就好比以下代码所表达的意思一样:

import java.util.HashMap;
import java.util.Map;

public class Main {

    public static void main(String[] args) {
        Map map = new HashMap<>();
        String key = "key1";
        map.put(key,"value1");
        key = "key2";
        System.out.println(map.get(key));
    }
}

 

以上验证了我们了解到的内容。

 

总结

所以我们定义ThreadLocal变量,应该在一开始就为其赋值,使用过程中避免修改其引用指向对象,而不是让它等于null。

正确的使用姿势——为其加一个final修饰符,建议:

final static ThreadLocal<String> threadLocal = new ThreadLocal<>();

使用完毕后调用其remove()方法,避免产生内存溢出或浪费。

 

 

完毕。

posted @ 2017-03-07 16:44  剑握在手  阅读(5129)  评论(1编辑  收藏  举报
返回顶部↑