ThreadLocal介绍和源码解析

时间:2025-02-14 15:15:35

                ThreadLocal类被称为线程本地变量类或者线程局部变量类。如果程序创建了一个ThreadLocal实例,那么在访问这个变量的值时,每个线程都会拥有一个独立的、自己的本地值。当线程各自操作自己的本地变量时,从而实现了线程安全。

 类 :

//无参
ThreadLocal<String> threadLocal = new ThreadLocal<>();
//静态方法 withInitial  全部线程可见
ThreadLocal<String> stringThreadLocal = (() -> "ok");

                       1.1私有的静态内部类 ThreadLocalMap

//看出Thread线程类中有个属性threadLocals
class Thread {
    //属性,存储threadLocal
     threadLocals = null;
    ...
}
class ThreadLocalMap{
    //有两个构造方法
    ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue);
    ThreadLocalMap(ThreadLocalMap parentMap);
    //储存值(重要)  Entry类为ThreadLocalMap的内部类,Entry(ThreadLocal<?> k, Object v) k为虚    
    //引用。其中value和T referent两个属性,value储存值,referent为ThreadLocal
    private Entry[] table;
}

        分析ThreadLocal类中的set(T value) 方法

public void set(T value) {
        //1. 由Thread类的静态方法currentThread(),获取当前线程的实例t
        Thread t = ();
        //2.  根据线程实例t,得到当前线程的属性ThreadLocalMap map
        ThreadLocalMap map = getMap(t);
        
        //3.判断map!=null,进入ThreadLocalMap类的set方法
        if (map != null)
            //3.1进入ThreadLocalMap类的set方法
            (this, value);
        else
            //4.1 进入createMap方法
            createMap(t, value);
}
set(ThreadLocal<?> key, Object value) {
            // 3.2 属性赋值tab
            Entry[] tab = table;
            // 3.3 得到tab的大小  tab初始大小为16
            int len = ;
            
            // 3.4 的二进制 & 1111(15)  0<=i<=15 
            int i =  & (len-1);
            
            // 3.5 i假定3, for语句的初始tab[3],当tab[i]==null结束循环,当i=15时,返回i=0
            for (Entry e = tab[i];
                 e != null;
                 e = tab[i = nextIndex(i, len)]) {
                //3.6 从Entry中得到,当前threadLocal对象
                ThreadLocal<?> k = ();
                
                //3.7 当前threadLocal对象与this相同,覆盖之前的值
                if (k == key) {
                     = value;
                    return;
                }
                // 3.8 当前threadLocal对象为null
                if (k == null) {
                    //清除无效的entry
                    replaceStaleEntry(key, value, i);
                    return;
                }
            }
            // 3.9 i=3 ,tab[3]=new Entry(key,value)
            tab[i] = new Entry(key, value);
            // 3.10 tab为10时,重hash,扩容
            int sz = ++size; 
            if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash();
}
void createMap(Thread t, T firstValue) {
        // 4.2 ThreadLocalMap双参构造赋值给当前线程类的属性threadLocals
         = new ThreadLocalMap(this, firstValue);
}

   分析ThreadLocal类中的get()方法 

public T get() {
        // 1.获取当前线程对象的实例
        Thread t = ();
        // 2.得到线程实例的threadLocals属性
        ThreadLocalMap map = getMap(t);
        // 为not null
        if (map != null) {
            // 3.1.得到当前ThreadLocal对象的Entry
             e = (this);
            // 3.2 Entry对象不为空
            if (e != null) {
                @SuppressWarnings("unchecked")
                // 3.3 得到Entry对象的value值,返回 
                T result = (T);
                return result;
            }
        }
        // 4.会调用SuppliedThreadLocal类重写的initialValue()方法,返回value,并且会将该值和当 
        // 前的Threadlocal对象储存到当前线程的threadLocals中
        return setInitialValue();
}

              ThreadLocal对象。1,线程安全,不需要加锁,避免锁的开销。2,节省内存。因为线程储存对象值,因此对象与线程的生命周期相同。3,线程隔离。

             使用时1.用static final 修饰 2.使用结束后调remove()方法。

             应用。1.从数据库的connection对象,放到ThreaLocal。。将requesFadce放到放到ThreaLocal中。对象或token(携带用户基本信息)放在ThreaLocal。。将SecurityContextImpl对象放到了ThreadLocal。(线程不安全)。

2.举例

// 继承ThreadLocal类
// (()->new TestBean("34")) 把对象储存起来
// get()每次得到对象引用是一样的
// ()->new TestBean("34") get()每次得到对象引用是不一样的
public class NamedThreadLocal<T> extends ThreadLocal<T> {
    private final String name;

    public NamedThreadLocal(String name) {
        (name, "Name must not be empty");
         = name;
    }

    public String toString() {
        return ;
    }
}

// 可继承的ThreadLocal类
// 使用主线程inheritableThreadLocals(ThreadLocalMap)
// 再开启子线程时,调用子线程的init(...)方法将主线程inheritableThreadLocals值复制一份创建
//  子线程的inheritableThreadLocals(ThreadLocalMap)
// 主线程储的对象,而子线程储对象的引用(value储的值,referent为创建的原始的threadLocal)
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
    /**
     * Computes the child's initial value for this inheritable thread-local
     * variable as a function of the parent's value at the time the child
     * thread is created.  This method is called from within the parent
     * thread before the child is started.
     * <p>
     * This method merely returns its input argument, and should be overridden
     * if a different behavior is desired.
     *
     * @param parentValue the parent thread's value
     * @return the child thread's initial value
     */
    protected T childValue(T parentValue) {
        return parentValue;
    }

    /**
     * Get the map associated with a ThreadLocal.
     *
     * @param t the current thread
     */
    ThreadLocalMap getMap(Thread t) {
       return ;
    }

    /**
     * Create the map associated with a ThreadLocal.
     *
     * @param t the current thread
     * @param firstValue value for the initial entry of the table.
     */
    void createMap(Thread t, T firstValue) {
         = new ThreadLocalMap(this, firstValue);
    }
}

// 继承继承ThreadLocal类
public class NamedInheritableThreadLocal<T> extends InheritableThreadLocal<T> {
    private final String name;

    public NamedInheritableThreadLocal(String name) {
        (name, "Name must not be empty");
         = name;
    }

    public String toString() {
        return ;
    }
}