InheritableThreadLocal源码阅读
说明
继前面《ThreadLocal源码阅读》知道ThreadLocal原理是获取当前线程Thread的一个Map,通过Entry封装 key为ThreadLocal对象自身 value为我们的值。但是ThreadLocal本身不是子线程共享的。InheritableThreadLocal就是为了解决子线程共享问题
如何实现子线程共享
我们知道线程变量都是通过Thread对象的threadLocals存储,其实除了这个线程对象还提供子线程共享的Map inheritableThreadLocals,创建子线程此变量会默认复制一份父线程此Map,注:是复制并不是继承 所以还是线程安全的,子线程set值并不会影响父线程或者其他子线程的值,默认是浅克隆,如果是操作ThreadLocal保存的引用对象则会实现修改,我们可以在childvalue自定义实现深克隆
/* 当前线程共享 子线程并不能共享 * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null; /* * * 创建线程时子线程会复制一份 */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
继承关系
重写的三个核心方法
/** * 复制父类ThreadLocalMap的时候调用 原路复制不做任何处理,比如浅克隆或者深克隆或者对复制的值做处理 * @param parentValue * @return */ protected T childValue(T parentValue) { return parentValue; } /** * 重写getMap获取线程对象的inheritableThreadLocals 后续复制也是复制此对象 具体可以看ThreadLocal源码 * * @param t the current thread */ ThreadLocal.ThreadLocalMap getMap(Thread t) { return t.inheritableThreadLocals; } /** * * @param t the current thread * @param firstValue value for the initial entry of the table. */ void createMap(Thread t, T firstValue) { t.inheritableThreadLocals = new ThreadLocal.ThreadLocalMap(this, firstValue); }
如何实现复制
<1>
//<2>构造函数实现复制 Thread thread=new Thread(new Runnable() { @Override public void run() { } });
<2>
<3>
private void init(ThreadGroup g, Runnable target, String name, long stackSize) { //<4>最后一个参数为true表示复制父线程 init(g, target, name, stackSize, null, true); }
<4>
private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc, boolean inheritThreadLocals) { if (name == null) { throw new NullPointerException("name cannot be null"); } this.name = name; //获得父线程也是创建子线程的线程 Thread parent = currentThread(); SecurityManager security = System.getSecurityManager(); if (g == null) { if (security != null) { g = security.getThreadGroup(); } if (g == null) { g = parent.getThreadGroup(); } } g.checkAccess(); if (security != null) { if (isCCLOverridden(getClass())) { security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION); } } g.addUnstarted(); this.group = g; this.daemon = parent.isDaemon(); this.priority = parent.getPriority(); if (security == null || isCCLOverridden(parent.getClass())) this.contextClassLoader = parent.getContextClassLoader(); else this.contextClassLoader = parent.contextClassLoader; this.inheritedAccessControlContext = acc != null ? acc : AccessController.getContext(); this.target = target; setPriority(priority); //inheritThreadLocals为true 同时inheritableThreadLocals不为空则复制父线程的 if (inheritThreadLocals && parent.inheritableThreadLocals != null) //<5>复制父线程的inheritableThreadLocals this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); /* Stash the specified stack size in case the VM cares */ this.stackSize = stackSize; /* Set thread ID */ tid = nextThreadID(); }
<5>
static ThreadLocal.ThreadLocalMap createInheritedMap(ThreadLocal.ThreadLocalMap parentMap) { //<6>复制 return new ThreadLocal.ThreadLocalMap(parentMap); }
<6>
private ThreadLocalMap(ThreadLocal.ThreadLocalMap parentMap) { ThreadLocal.ThreadLocalMap.Entry[] parentTable = parentMap.table; int len = parentTable.length; setThreshold(len); table = new ThreadLocal.ThreadLocalMap.Entry[len]; //遍历inheritableThreadLocals的值 for (int j = 0; j < len; j++) { ThreadLocal.ThreadLocalMap.Entry e = parentTable[j]; if (e != null) { //这里获取到的是InheritableThreadLocal ThreadLocal<Object> key = (ThreadLocal<Object>) e.get(); if (key != null) { //调用childValue 被重写,默认是原值返回 表示是浅克隆 Object value = key.childValue(e.value); //用新的Entry封装保存到当前map ThreadLocal.ThreadLocalMap.Entry c = new ThreadLocal.ThreadLocalMap.Entry(key, value); int h = key.threadLocalHashCode & (len - 1); while (table[h] != null) h = nextIndex(h, len); table[h] = c; size++; } } } }
浅克隆的体现
package other.sort; import java.io.IOException; /** * @author liqiang * @date 2022/2/23 */ public class psvm { String name; String age; public psvm(String name, String age) { this.name = name; this.age = age; } @Override public String toString() { return "psvm{" + "name='" + name + '\'' + ", age='" + age + '\'' + '}'; } public static void main(String[] args) throws Exception { ThreadLocal<psvm> threadLocal = new InheritableThreadLocal(); psvm zs = new psvm("zs", "12"); threadLocal.set(zs); new Thread(()->{ psvm psvm = threadLocal.get(); System.out.println(threadLocal.get()); psvm.age= "13"; }).start(); Thread.sleep(3000); System.out.println("main"+threadLocal.get()); System.in.read(); } }