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

基本实践
ThreadLocal的不可继承性指的是子线程无法继承获取到父线程中的值。而InheritableThreadLocal则通过继承ThreadLocal类实现了可继承性。测试代码如下所示
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 
 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)public class InheritableThreadLocalDemo {
 
 
 
 
 @Test
 public void test1() {
 System.out.println("\n--------------------------- Test 1 ---------------------------");
 ThreadLocal<String> userInfo = new ThreadLocal<>();
 userInfo.set("Aaron");
 new Thread( ()-> System.out.println("<子线程> userInfo: " + userInfo.get()) )
 .start();
 System.out.println("<父线程> userInfo: " + userInfo.get());
 }
 
 
 
 
 @Test
 public void test2() {
 System.out.println("\n--------------------------- Test 2 ---------------------------");
 InheritableThreadLocal<String> userInfo = new InheritableThreadLocal<>();
 userInfo.set("Aaron");
 new Thread( ()-> System.out.println("<子线程> userInfo: " + userInfo.get()) )
 .start();
 System.out.println("<父线程> userInfo: " + userInfo.get());
 }
 
 }
 
 | 
测试结果如下,符合预期

基本原理
其基本原理也很简单,该类继承了ThreadLocal并重写了下述的三个方法。众所周知,ThreadLocal是通过Thread类中ThreadLocal.ThreadLocalMap类型的threadLocals字段实现线程本地存储的。而InheritableThreadLocal则是使用Thread类中ThreadLocal.ThreadLocalMap类型的inheritableThreadLocals字段。其实现如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 
 | 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实例创建过程中相关源码部分实现如下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 
 | public class Thread implements Runnable {
 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) {
 ...
 
 Thread parent = currentThread();
 ...
 
 if (inheritThreadLocals && parent.inheritableThreadLocals != null)
 
 this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
 ...
 }
 
 }
 
 | 
前面提到子线程虽然继承了父线程的值,但其是通过浅拷贝的方式进行的。下面通过示例代码来验证下
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 
 | @FixMethodOrder(MethodSorters.NAME_ASCENDING)public class InheritableThreadLocalDemo {
 
 @Test
 public void test3() throws Exception {
 System.out.println("\n--------------------------- Test 3 ---------------------------");
 InheritableThreadLocal<String> userInfo = new InheritableThreadLocal<>();
 userInfo.set("Aaron");
 System.out.println("<父线程> userInfo #1: " + userInfo.get());
 Thread thread = new Thread( ()-> {
 System.out.println("<子线程> userInfo #2: " + userInfo.get());
 userInfo.set("Bob");
 System.out.println("<子线程> userInfo #3: " + userInfo.get());
 } );
 thread.start();
 thread.join();
 System.out.println("<父线程> userInfo #4: " + userInfo.get());
 }
 
 @Test
 public void test4() throws Exception {
 System.out.println("\n--------------------------- Test 4 ---------------------------");
 InheritableThreadLocal<User> userInfo = new InheritableThreadLocal<>();
 userInfo.set( new User("Aaron") );
 System.out.println("<父线程> userInfo #1: " + userInfo.get());
 Thread thread = new Thread( ()-> {
 System.out.println("<子线程> userInfo #2: " + userInfo.get());
 userInfo.get().setName("Bob");
 System.out.println("<子线程> userInfo #3: " + userInfo.get());
 } );
 thread.start();
 thread.join();
 System.out.println("<父线程> userInfo #4: " + userInfo.get());
 }
 
 @AllArgsConstructor
 @Data
 private static class User {
 private String name;
 }
 
 }
 
 | 
测试结果如下,符合预期

参考文献
- Java并发编程之美 翟陆续、薛宾田著