public class ThreadLocalCase1 {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Random random = new Random();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
int value = random.nextInt(10000);
threadLocal.set(value);
System.out.println(Thread.currentThread().getName() + "开始执行,放入值,值为 : " + value);
System.out.println(Thread.currentThread().getName() + "结束执行,进行取值,值为 : " + threadLocal.get());
});
thread.setName("thread-" + i);
thread.start();
}
}
}
结果
thread-0开始执行,放入值,值为 : 7406
thread-4开始执行,放入值,值为 : 5258
thread-3开始执行,放入值,值为 : 9672
thread-2开始执行,放入值,值为 : 8583
thread-1开始执行,放入值,值为 : 9311
thread-2结束执行,进行取值,值为 : 8583
thread-3结束执行,进行取值,值为 : 9672
thread-4结束执行,进行取值,值为 : 5258
thread-0结束执行,进行取值,值为 : 7406
thread-1结束执行,进行取值,值为 : 9311
实现了线程之间的隔离性
public class ThreadLocalCase2 {
private static ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
Random random = new Random();
int value = random.nextInt(10000);
threadLocal.set(value);
System.out.println(Thread.currentThread().getName() + "放入值,值为 : " + value);
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
});
thread.setName("thread-1");
thread.start();
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
}
}
结果
main放入值,值为 : 3831
main进行取值,值为 : 3831
thread-1进行取值,值为 : null
发现主线程向ThreadLocal
设置值,每个子线程再取值时为null,这时需要换用InheritableThreadLocal
public class ThreadLocalCase2 {
private static InheritableThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
Random random = new Random();
int value = random.nextInt(10000);
threadLocal.set(value);
System.out.println(Thread.currentThread().getName() + "放入值,值为 : " + value);
Thread thread = new Thread(() -> {
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
});
thread.setName("thread-1");
thread.start();
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
}
}
结果
main放入值,值为 : 2046
main进行取值,值为 : 2046
thread-1进行取值,值为 : 2046
public class ThreadLocalCase3 {
private static ExecutorService executor = Executors.newFixedThreadPool(2);
private static InheritableThreadLocal<Integer> threadLocal = new InheritableThreadLocal<>();
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Random random = new Random();
int value = random.nextInt(10000);
threadLocal.set(value);
System.out.println(Thread.currentThread().getName() + "放入值,值为 : " + value);
executor.execute(() -> {
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
});
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
threadLocal.remove();
}
}
}
结果
main放入值,值为 : 8525
main进行取值,值为 : 8525
main放入值,值为 : 7802
main进行取值,值为 : 7802
pool-1-thread-1进行取值,值为 : 8525
main放入值,值为 : 3570
pool-1-thread-2进行取值,值为 : 7802
main进行取值,值为 : 3570
pool-1-thread-1进行取值,值为 : 8525
main放入值,值为 : 5081
main进行取值,值为 : 5081
pool-1-thread-2进行取值,值为 : 7802
main放入值,值为 : 4829
main进行取值,值为 : 4829
pool-1-thread-1进行取值,值为 : 8525
结果发现线程池取出了两次7802和三次8525,主线程中设置的3570、5081、4829在线程池中没有被取出,发生了错误。
这是由于InheritableThreadLocal会保证子线程能读取父线程中的数据,但线程池中的核心线程是复用的,所以有可能会发生重复读取的情况。
public class ThreadLocalCase4 {
private static ExecutorService executor = Executors.newFixedThreadPool(2);
private static TransmittableThreadLocal<Integer> threadLocal = new TransmittableThreadLocal<>();
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Random random = new Random();
int value = random.nextInt(10000);
threadLocal.set(value);
System.out.println(Thread.currentThread().getName() + "放入值,值为 : " + value);
executor.execute(TtlRunnable.get(() -> {
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
}));
System.out.println(Thread.currentThread().getName() + "进行取值,值为 : " + threadLocal.get());
threadLocal.remove();
}
}
}
结果
main放入值,值为 : 974
main进行取值,值为 : 974
main放入值,值为 : 4545
main进行取值,值为 : 4545
main放入值,值为 : 5901
pool-1-thread-1进行取值,值为 : 974
main进行取值,值为 : 5901
pool-1-thread-1进行取值,值为 : 5901
pool-1-thread-2进行取值,值为 : 4545
main放入值,值为 : 3716
main进行取值,值为 : 3716
pool-1-thread-1进行取值,值为 : 3716
main放入值,值为 : 2452
main进行取值,值为 : 2452
pool-1-thread-2进行取值,值为 : 2452
结果是即使线程池的线程被复用,读取的结果也是正常的
public class Thread implements Runnable {
//省略....
/*
* 当前线程的ThreadLocalMap,主要存储该线程自身的ThreadLocal
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
//省略....
}
ThreadLocal
是一个泛型类,用于存储每个线程的本地变量副本。ThreadLocal
实例获取和操作自己的变量副本,避免了多线程间的资源竞争。ThreadLocalMap
是ThreadLocal
的内部静态类,用于存储线程局部变量。ThreadLocalMap
实例,用来存储该线程的ThreadLocal
变量。ThreadLocalMap
以ThreadLocal
实例作为键,实际存储的值作为值。InheritableThreadLocal重写的方法
public class InheritableThreadLocal<T> extends ThreadLocal<T> {
protected T childValue(T parentValue) {
return parentValue;
}
ThreadLocalMap getMap(Thread t) {
return t.inheritableThreadLocals;
}
void createMap(Thread t, T firstValue) {
t.inheritableThreadLocals = new ThreadLocalMap(this, firstValue);
}
}
Thread结构
public class Thread implements Runnable {
//省略....
/*
* 存储本线程自身的ThreadLocal
*/
ThreadLocal.ThreadLocalMap threadLocals = null;
/*
* 从父线程集成而来的ThreadLocalMap,
*/
ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
//省略....
}
主线程中调用InheritableThreadLocal的set方法
set依旧是ThreadLocal
中
public void set(T value) {
Thread t = Thread.currentThread();
//被InheritableThreadLocal重写,第一次为空
ThreadLocalMap map = getMap(t);
if (map != null) {
map.set(this, value);
} else {
//被InheritableThreadLocal重写,创建ThreadLocalMap赋值给inheritableThreadLocals变量
createMap(t, value);
}
}
这时就是Thread中的inheritableThreadLocals变量存储ThreadLocalMap
子线程初始化
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize) {
init(g, target, name, stackSize, null, true);
}
private void init(ThreadGroup g, Runnable target, String name,
long stackSize, AccessControlContext acc,
boolean inheritThreadLocals) {
//省略....
//inheritThreadLocals为true
//parent.inheritableThreadLocals就是在主线程进行set的时候生成为所以不为null
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
this.inheritableThreadLocals =
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
//省略....
}
ThreadLocal.createInheritedMap(parent.inheritableThreadLocals)
就是将主线程的ThreadLocalMap
拷贝到子线程中
static ThreadLocalMap createInheritedMap(ThreadLocalMap parentMap) {
return new ThreadLocalMap(parentMap);
}
/**
* 将父线程的ThreadLocalMap拷贝到此线程中
*/
private ThreadLocalMap(ThreadLocalMap parentMap) {
//父线程的ThreadLocalMap的entry数组
Entry[] parentTable = parentMap.table;
int len = parentTable.length;
setThreshold(len);
// 这里的table就是此线程中的ThreadLocalMap的entry数组
table = new Entry[len];
// 循环进行拷贝 parentMap 的记录
for (int j = 0; j < len; j++) {
Entry e = parentTable[j];
if (e != null) {
@SuppressWarnings("unchecked")
ThreadLocal<Object> key = (ThreadLocal<Object>) e.get();
if (key != null) {
//这里被InheritableThreadLocal重写,直接返回value,不做任何操作
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] = c;
size++;
}
}
}
}