|
针对ThreadLocal不可继承的特点,Java还引入了InheritableThreadLocal类,顾名思义其是可以继承的

abstract.jpeg
基本实践
ThreadLocal的不可继承性指的是子线程无法继承获取到父线程中的值。而InheritableThreadLocal则通过继承ThreadLocal类实现了可继承性。测试代码如下所示
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class InheritableThreadLocalDemo {
/**
* ThreadLocal继承性测试
*/
@Test
public void test1() {
System.out.println("\n--------------------------- Test 1 ---------------------------");
ThreadLocal<String> userInfo = new ThreadLocal<>();
userInfo.set(&#34;Aaron&#34;);
new Thread( ()-> System.out.println(&#34;<子线程> userInfo: &#34; + userInfo.get()) )
.start();
System.out.println(&#34;<父线程> userInfo: &#34; + userInfo.get());
}
/**
* InheritableThreadLocal继承性测试
*/
@Test
public void test2() {
System.out.println(&#34;\n--------------------------- Test 2 ---------------------------&#34;);
InheritableThreadLocal<String> userInfo = new InheritableThreadLocal<>();
userInfo.set(&#34;Aaron&#34;);
new Thread( ()-> System.out.println(&#34;<子线程> userInfo: &#34; + userInfo.get()) )
.start();
System.out.println(&#34;<父线程> userInfo: &#34; + userInfo.get());
}
}
测试结果如下,符合预期

figure 1.jpeg
基本原理
其基本原理也很简单,该类继承了ThreadLocal并重写了下述的三个方法。众所周知,ThreadLocal是通过Thread类中ThreadLocal.ThreadLocalMap类型的threadLocals字段实现线程本地存储的。而InheritableThreadLocal则是使用Thread类中ThreadLocal.ThreadLocalMap类型的inheritableThreadLocals字段。其实现如下
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);
}
}
而其继承性的实现也很简单,即在子线程创建阶段通过init方法将将父线程的inheritableThreadLocals浅拷贝到子线程中,Thread实例创建过程中相关源码部分实现如下
public class Thread implements Runnable {
public Thread(Runnable target) {
init(null, target, &#34;Thread-&#34; + 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) {
...
// 获取当前线程, 即父线程
Thread parent = currentThread();
...
// 父线程的inheritableThreadLocals变量不为空
if (inheritThreadLocals && parent.inheritableThreadLocals != null)
// 将父线程的inheritableThreadLocals浅拷贝到子线程
this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
...
}
}
前面提到子线程虽然继承了父线程的值,但其是通过浅拷贝的方式进行的。下面通过示例代码来验证下
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class InheritableThreadLocalDemo {
@Test
public void test3() throws Exception {
System.out.println(&#34;\n--------------------------- Test 3 ---------------------------&#34;);
InheritableThreadLocal<String> userInfo = new InheritableThreadLocal<>();
userInfo.set(&#34;Aaron&#34;);
System.out.println(&#34;<父线程> userInfo #1: &#34; + userInfo.get());
Thread thread = new Thread( ()-> {
System.out.println(&#34;<子线程> userInfo #2: &#34; + userInfo.get());
userInfo.set(&#34;Bob&#34;);
System.out.println(&#34;<子线程> userInfo #3: &#34; + userInfo.get());
} );
thread.start();
thread.join();
System.out.println(&#34;<父线程> userInfo #4: &#34; + userInfo.get());
}
@Test
public void test4() throws Exception {
System.out.println(&#34;\n--------------------------- Test 4 ---------------------------&#34;);
InheritableThreadLocal<User> userInfo = new InheritableThreadLocal<>();
userInfo.set( new User(&#34;Aaron&#34;) );
System.out.println(&#34;<父线程> userInfo #1: &#34; + userInfo.get());
Thread thread = new Thread( ()-> {
System.out.println(&#34;<子线程> userInfo #2: &#34; + userInfo.get());
userInfo.get().setName(&#34;Bob&#34;);
System.out.println(&#34;<子线程> userInfo #3: &#34; + userInfo.get());
} );
thread.start();
thread.join();
System.out.println(&#34;<父线程> userInfo #4: &#34; + userInfo.get());
}
@AllArgsConstructor
@Data
private static class User {
private String name;
}
}
测试结果如下,符合预期

figure 2.jpeg
参考文献
欢迎关注我的公众号(个人简介处有微信公众号名称),一起去寻找文明的痕迹~ |
|