1 类ThreadLocal的使用
变量值的共享可以使用public static
变量的形式,所有的线程都是用同一个public static
变量。而ThreadLocal
主要解决的就是每个线程绑定自己的值,可以将ThreadLocal
类比喻成全局存放的盒子,盒子中可以存储每个线程的私有数据。
1.1 验证线程变量的隔离性
public class Tools {
public static ThreadLocal<Date> t1 = new ThreadLocal<>();
}
public class ThreadA extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
if (Tools.t1.get() == null) {
Tools.t1.set(new Date());
}
System.out.println("A " + Tools.t1.get().getTime());
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class ThreadB extends Thread {
@Override
public void run() {
try {
for (int i = 0; i < 20; i++) {
if (Tools.t1.get() == null) {
Tools.t1.set(new Date());
}
System.out.println("B " + Tools.t1.get().getTime());
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class Run {
public static void main(String[] args) {
try {
ThreadA threadA = new ThreadA();
threadA.start();
Thread.sleep(1000);
ThreadB threadB = new ThreadB();
threadB.start();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
线程threadA
和threadB
都向t1
对象中set()
数据值,但每个线程还是能取出自己的数据。
1.2 解决get()返回null问题
public class Tools {
public static ThreadLocal<Date> t1 = new ThreadLocal<Date>() {
@Override
protected Date initialValue() {
return new Date();
};
};
}
1.3 实现机制
- 每个
Thread
对象内部都维护了一个ThreadLocalMap
这样一个ThreadLocal
的Map
,可以存放若干个ThreadLocal
。
ThreadLocal.ThreadLocalMap threadLocals = null;
- 当我们在调用
get()
方法的时候,先获取当前线程,然后获取到当前线程的ThreadLocalMap
对象,如果非空,那么取出ThreadLocal
的value
,否则进行初始化,初始化就是将initialValue
的值set
到ThreadLocal
中。
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;
}
}
return setInitialValue();
}
- 当我们调用
set()
方法的时候,就是将值设置进ThreadLocal
中。 - 总结:当我们调用get方法的时候,其实每个当前线程中都有一个
ThreadLocal
。每次获取或者设置都是对该ThreadLocal
进行的操作,是与其他线程分开的。 - 应用场景:当很多线程需要多次使用同一个对象,并且需要该对象具有相同初始化值的时候最适合使用
ThreadLocal
。
2 类InheritableThreadLocal的使用
public class InheritableThreadLocal<T> extends ThreadLocal<T> {}
使用类InheritableThreadLocal
可以在子线程中取得父线程继承下来的值。在继承的同时还可以对值进行进一步的处理。
public class InheritableThreadLocalExt extends InheritableThreadLocal<Long> {
@Override
protected Long initialValue() {
return new Date().getTime();
}
@Override
protected Long childValue(Long parentValue) {
return parentValue * 2;
}
}
);
}
@Override
protected Long childValue(Long parentValue) {
return parentValue * 2;
}
}