java.lang.ThreadLocal源码分析

ThreadLocal类提供线程本地变量,为变量在每个线程创建一个副本,每个线程可以访问自己内部的副本变量。

比如,有这样一个需求,需要为每个线程创建一个独一无二的标识,这个标识在第一次调用ThreadId.get()的时候生成,在随后的调用中不会再改变。

public class ThreadId {
    private static final AtomicInteger nextId = new AtomicInteger(0);
    
    private static final ThreadLocal<Integer> threadId =
            new ThreadLocal<Integer>() {
                @Override
                protected Integer initialValue() {
                    return nextId.getAndIncrement();
                }
    };
    public static int get() {
        return threadId.get();
    }
}

类声明:

public class ThreadLocal<T> {}

实例变量和相关的一个方法:

//用于ThreadLocalMap
private final int threadLocalHashCode = nextHashCode();

//下一个hash code,从0开始
private static AtomicInteger nextHashCode = new AtomicInteger();

//hash增量
private static final int HASH_INCREMENT = 0x61c88647;

//在获取下一个hash code
private static int nextHashCode() {
    return nextHashCode.getAndAdd(HASH_INCREMENT);
}

构造方法:

public ThreadLocal() {}

重要的操作:

//线程本地变量的初始化方法,访问修饰符为protected是为了让程序员可以覆盖这个方法,默认是返回null,也就是说默认的线程本地变量值为null
protected T initialValue() {
    return null;
}

get操作

//获取当前线程的本地变量
public T get() {
    Thread t = Thread.currentThread();//得到当前的线程
    ThreadLocalMap map = getMap(t);//根据当前线程获得一个ThreadLocalMap
    if (map != null) {//如果不为空
        ThreadLocalMap.Entry e = map.getEntry(this);//根据当前对象获得Entry
        if (e != null) {//如果本地变量存在,返回值
        @SuppressWarnings("unchecked")
        T result = (T)e.value;
        return result;
        }
    }
    //否则调用setInitialValue方法
    return setInitialValue();
}

getMap方法

//返回当前线程的threadLocals变量
ThreadLocalMap getMap(Thread t) {
    return t.threadLocals;
}

threadLocals的声明

//其实就是一个ThreadLocalMap类型的变量
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap

//ThreadLocalMap里有Entry内部类,用于存放键值对
static class ThreadLocalMap {
    static class Entry extends WeakReference<ThreadLocal<?>> {
        Object value;

        Entry(ThreadLocal<?> k, Object v) {
        super(k);
        value = v;
    }
    .....以下省略
}

setInitialValue方法

private T setInitialValue() {
    T value = initialValue();//调用initialValue方法,初始化本地变量的值,如果不覆盖该方法,返回null
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);//根据当前线程获取ThreadLocalMap
    if (map != null)//如果map不为空
        map.set(this, value);//设置键值对
    else
        createMap(t, value);//否则创建map
     return value;
}

createMap方法

void createMap(Thread t, T firstValue) {
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

至此可以知道ThreadLocal如何为每个线程创建变量副本了,每个线程Thread内部有一个ThreadLocal.ThreadLocalMap类型的成员变量threadLocals,这个threadLocals就是用来存储实际的变量副本的,存储以ThreadLocal为键,本地线程变量为值的键值对。

remove操作

//先获取当前线程的ThreadLocalMap,然后删除当前ThreadLocal对象
public void remove() {
    ThreadLocalMap m = getMap(Thread.currentThread());
    if (m != null)
        m.remove(this);
}
原文地址:https://www.cnblogs.com/13jhzeng/p/5913762.html