ThreadLocal

介绍

ThreadLocal为每个使用该变量的线程提供独立的变量副本,所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。

ThreadLocal像是一个map,map的键就是每一个线程,值就是变量副本

使用

public class ThreadLocalDemo {
    private ThreadLocal<Integer> threadLocal = ThreadLocal.withInitial(() -> 0);

    public Integer getNext() {
        Integer integer = threadLocal.get();
        threadLocal.set(++integer);
        return integer;
    }

    public static void main(String[] args) {
        ThreadLocalDemo threadLocalDemo = new ThreadLocalDemo();
        for (int i = 0; i < 3; i++) {
            new Thread(() -> {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + threadLocalDemo.getNext());
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

上面的代码中,每一个线程的值都是从0开始递增,各个线程之间互不影响。

原理解析

首先查看get()方法的源代码:

public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            // 这里可以看到最终的值是从这里拿到的,也就是说值会存在ThreadLocal下面的ThreadLocalMap里面的Entry里面的value里面	
            T result = (T)e.value;    
            return result;
        }
    }
    return setInitialValue();
}


private T setInitialValue() {
    T value = initialValue();   // 获取初始值 这个是用户自己重写的
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
    return value;
}

void createMap(Thread t, T firstValue) {
    // 这个创建ThreadLocalMap的方法比较有趣的是它将创建好后的map赋值给了当前线程的一个属性
 	// 而在Thread类中确实有这样一个属性,如下。因此ThreadLocalMap是属于每一个线程的
    t.threadLocals = new ThreadLocalMap(this, firstValue);   
}

ThreadLocal.ThreadLocalMap threadLocals = null;
posted @ 2019-12-15 21:26  Jin同学  阅读(386)  评论(0编辑  收藏  举报