ThreadLocal、InheritableThreadLocal详解

Karima ·
更新时间:2024-11-13
· 851 次阅读

ThreadLocal、InheritableThreadLocal详解

多线程访问同一个共享变量时,容易出现并发冲突,为了保证线程的安全,一般使用者在访问共享变量时,需要进行适量的同步。而ThreadLocal提供了线程的私有变量,每个线程都可以通过set()get()来对这个私有变量进行操作,但不会和其他线程的私有变量进行冲突,实现了线程的数据隔离。InheritableThreadLocal作用和ThreadLocal相同,同时增加了一个功能,可以共享父线程InheritableThreadLocal提供的私有部变量,下面从源码角度,分别介绍这两个类。

ThreadLocal

下面是TheadLocal一段简单使用的代码。线程a、线程b内部都维护了一个String类型变量,通过ThreadLocal 变量thl的get、set方法可以对其进行访问和修改。

public class Main{ static ThreadLocal thl = new ThreadLocal(); static void print(){ System.out.println(thl.get()); } public static void main(String args[]) throws Exception{ Thread a = new Thread(new Runnable(){ @Override public void run() { thl.set("ThreadA variable"); print(); } }); Thread b = new Thread(new Runnable(){ @Override public void run() { thl.set("ThreadB variable"); print(); } }); a.start(); b.start(); a.join(); b.join(); } } //结果可能是 ThreadA variable ThreadB variable //或者是 ThreadB variable ThreadA variable get、set方法

每个线程里面均维护有threadLocals和inheritableLocals两个变量,两个变量均为ThreadLocalMap类(类似HashMap),调用ThreadLocal的set、get方法,其实就是对threadLocalMap进行修改和访问操作。同时也就解释了ThreadLocal提供的变量是线程私有的原因。

public void set(T value) { //获取当前线程 Thread t = Thread.currentThread(); //获取线程的ThreadLocalMap变量 ThreadLocalMap map = getMap(t); //key为ThreadLocal变量、value为T变量,添加进ThreadLocalMap变量 if(map != null) map.set(this, value); else createMap(t,value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); } 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") T result = (T)e.value; return result; } } } InheritableThreadLocal

下面这段代码,说明ThreadLocal不支持继承性

public class TestThreadLocal{ public static ThreadLocal threadLocal = new ThreadLocal(); public static void main(String[] args) throws Exception { threadLocal.set("Hello World"); Thread t = new Thread(new Runnable(){ @Override public void run() { System.out.println("t:" + threadLocal.get()); } }); t.start(); t.join(); System.out.println("Main:" + threadLocal.get()); } } //t:null //Main:Hello World

而相比于ThreadLocalInheritableThreadLocal恰如其名称所描述的支持,子线程共享父线程InheritableThreadLocal提供的私有变量。

下面解释InheritableThreadLocal的共享原理,线程在初始化的时候,如果父线程的inheritableThreadLocals不为空,则会调用createInheritedMap函数, 最终调用ThreadLocalMap的一个私有构造函数,用于将父线程的InheritableThreadLocal变量移植(直接复制引用,并没有重新开辟内存空间)到子线程的InheritableThreadLocal变量,达到一个变量共享的目的。

//线程初始化函数 public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } private void init(ThreadGroup g, Runnable target, String name, long stackSize, AcessControlContext acc) { Thread parent = currentThread(); if(parent.inheritableThreadLocals != null) this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); this.stackSize = stackSize; tid = nextThreadID(); } static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap){ return new ThreadLocalMap(parentMap); } private ThreadLocalMap(ThreadLocalMap parentMap) { Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); for(int j = 0; j < len; j++) { Entry e = parentTable[j]; if(e != null) { @SuppressWarnings("unchecked") ThreadLocal key = (ThreadLocal) e.get(); if(key != null) { Object value = key.childValue(e.value); Entry c = new Entry(key, value); int h = key.threadLocalHashCode & (len -1); while(table[h] != null) { h = nextIndex(h, len); } table[h] = e; size++; } } } } 参考资料

Java并发编程之美


作者:zycxnanwang



threadlocal

需要 登录 后方可回复, 如果你还没有账号请 注册新账号