针对ThreadLocal不可继承的特点,Java还引入了InheritableThreadLocal类,顾名思义其是可以继承的
基本实践
ThreadLocal的不可继承性指的是子线程无法继承获取到父线程中的值。而InheritableThreadLocal则通过继承ThreadLocal类实现了可继承性。测试代码如下所示
1 2 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字段。其实现如下
1 2 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实例创建过程中相关源码部分实现如下
1 2 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); ... }
}
|
前面提到子线程虽然继承了父线程的值,但其是通过浅拷贝的方式进行的。下面通过示例代码来验证下
1 2 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并发编程之美 翟陆续、薛宾田著