ThreadLocal

一:介绍 #

ThreadLocal直译为线程局部变量,或许将它命名为ThreadLocalVariable更为合适。其主要作用就是实现线程本地存储功能,通过线程本地资源隔离,解决多线程并发场景下线程安全问题

类ThreadLocal 主要解决的就是每个线程绑定自己的值,可以将ThreadLocal类比喻成全局存放数据的盒子,盒子中可以存放每个线程 的私有数据

二:用法举例 #

public class ToolsThreadLocal {

    public static ThreadLocal t1 = new ThreadLocal();

}



public class ThreadLocalA extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            ToolsThreadLocal.t1.set("thread a "+i);
            System.out.println(ToolsThreadLocal.t1.get());
        }
    }
}


public class ThreadLocalB extends Thread {
    @Override
    public void run() {
        for (int i = 0; i < 50; i++) {
            ToolsThreadLocal.t1.set("thread b "+i);
            System.out.println(ToolsThreadLocal.t1.get());
        }
    }
}

public class ThreadLocalRun {
    public static void main(String[] args) {
        ThreadLocalA  threadLocalA = new ThreadLocalA();
        threadLocalA.start();

        ThreadLocalB  threadLocalB = new ThreadLocalB();
        threadLocalB.start();

        for (int i = 0; i < 50; i++) {
            ToolsThreadLocal.t1.set("thread main "+i);
            System.out.println(ToolsThreadLocal.t1.get());
        }
    }
}

三:应用场景 #

针对ThreadLocal而言,由于其适合隔离、线程本地存储等特性,因此天然的适合一些Web应用场景,比如下面所列举的例子:

  • 代替参数显式传递(很少使用)
  • 存储全局用户登录信息
  • 存储数据库连接,以及Session等信息
  • Spring事务处理方案

四:api #

  • get
public T get() {
    // 获取当前操作线程
    Thread t = Thread.currentThread();
    // 调用getMap方法,返回当前线程的实例变量threadLocals值
    ThreadLocalMap map = getMap(t);
    // 如果返回map不为空,返回map中所存储的以当前ThreadLocal对象为key的值
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    // 如果map为空进行map值的初始化
    return setInitialValue();
}
 
ThreadLocalMap getMap(Thread t) {
    // 返回传入线程(当前线程)中成员变量的threadLocals值
    return t.threadLocals;
}
 
private T setInitialValue() {
    // 调用initialValue()方法设置初始值,默认不设置任何值,可以在创建ThreadLocal
    // 对象时被重写进行初始化,只会进行一次初始化。
    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) {
    // 初始化当前线程对象实例变量threadLocals的值,Map所对应的key为当前ThreadLocal对象
    t.threadLocals = new ThreadLocalMap(this, firstValue);
}
  • set
public void set(T value) {
    // 获取当前线程对象
    Thread t = Thread.currentThread();
    // 调用getMap方法,传入当前对象的值,获取当前线程的实例变量threadLocals值
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        // 如果map为空,创建ThreadLocalMap
        createMap(t, value);
}