ThreadLocal of JDK source code learning series

1. Storage structure

insert image description here
The member variable threadLocals of the Thread class is a Map structure. Each thread has an independent ThreadLoaclMap object, which stores the Entry object. Its key is the ThreadLocal object we usually define, and the value is the value in it, because it may be in the same Multiple ThreadLocals are defined in a thread, so each index subscript in the figure corresponds to one of the ThreadLocal object information.

2. Core member variables

// 每个ThreadLocal对象都分配一个hashCode,用于确定上图中threadLocals的桶位
private final int threadLocalHashCode = nextHashCode();

/ 每次生成新的ThreadLocal对象都会用它来生成hashcode
private static AtomicInteger nextHashCode =
    new AtomicInteger();

3. Member methods

public void set(T value) {
    
    
        Thread t = Thread.currentThread();
        // 获取当前线程的threadLocals对象,即上图中的数组对象
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
           // 如果第一次获取,则创建一个新的threadLocals
            createMap(t, value);
    }

ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    
    
            // table是Entry对象,它是一个key-value映射表结构,
            // 其中的key存储我们定义的ThreaLocal
            // value存储ThreadLocal设置的value
            table = new Entry[INITIAL_CAPACITY]; // 默认数组长度16
            int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
            table[i] = new Entry(firstKey, firstValue);
            size = 1;
            setThreshold(INITIAL_CAPACITY);
        }

get method

public T get() {
    
    
      // 当前线程
        Thread t = Thread.currentThread();
       // 拿到当前线程对应的ThreadLocalMap对象(threadLocals) 
        ThreadLocalMap map = getMap(t);
        if (map != null) {
    
    
           // 进入这里,说明当前线程已经创建过ThreadLocalMap对象了
           // 通过this,即当前的ThreadLocal获取到下标对应的Entry对象
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null) {
    
    
                @SuppressWarnings("unchecked")
                 // 说明当前ThreadLocal存在,直接放回它关联的value
                T result = (T)e.value;
                return result;
            }
        }
         // 走到这里,需要初始化当前线程的ThreadLocalMap对象,
         // 或者当前线程的ThreadLocal还未生成Entry对象到ThreadLocalMap中
        return setInitialValue();
    }


setInitialValue method

 private T setInitialValue() {
    
    
       // 调用初始化方法,一般都由我们自己重写实现
        T value = initialValue();
        Thread t = Thread.currentThread();
       // 获取当前线程内部的threadLocals(threadLocalMap对象)
        ThreadLocalMap map = getMap(t);
        if (map != null)
           // 将定义的ThreadLocal对象放到threadLocals数组对应的下标中
            map.set(this, value);
        else
           // 如果ThreadLocalMap没初始化,则进入创建方法
            createMap(t, value);
        return value;
    }

void createMap(Thread t, T firstValue) {
    
    
    // 创建一个ThreadLocalMap对象,key-value结构
    // 其中key= this 即当前threadLocal对象
    // value = 当前threadLocal相关的局部变量
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}

set method

 public void set(T value) {
    
    
       // 跟上面setInitialValue方法差不多
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

remove method

public void remove() {
    
    
       // 获取当前线程对应的ThreadLocalMap对象
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
            // this即定义的TheadLocal对象,将其从ThreadLocalMap中移除
             m.remove(this);
     }

4. Entry inner class

 static class Entry extends WeakReference<ThreadLocal<?>> {
    
    
            /** The value associated with this ThreadLocal. */
            Object value;

            Entry(ThreadLocal<?> k, Object v) {
    
    
                super(k);
                value = v;
            }
        }

It is found that it inherits the weak reference WeakReference class. We know that the concept of weak reference is that if the object is a weak reference, then if it is detected from GCRoot that it has no strong reference, then the current ThreadLocal object will be garbage collected at the next gc, so that the design can avoid A memory leak occurs.
Seeing this, I don’t know if you have the same question as me. Since this ThreadLocal is a weak reference, that is, it will be recycled every time garbage collection is made, isn’t it very dangerous to call its get method to get the value every time in the program? Why, because it was garbage collected. In fact, this is not the case, because every request has a thread that references this ThreadLocal object, that is our business thread, only when a complete request is over, there is no strong reference at this time, and garbage collection is allowed at this time , so there is no problem.

Guess you like

Origin blog.csdn.net/huangdi1309/article/details/124570800
Recommended