为了方便且更加安全的进行多线程编程,jdk引入ThreadLocal和InheritableThreadLocal两个类,以供开发人员进行多线程之间的数据传递和数据共享。InheritableThreadLocal是ThreadLocal的子类,它可以实现子线程共享父线程的变量。
ThreadLocal:
private static ThreadLocal<String> testThreadLocal = new ThreadLocal<>();/*// 创建时可重写初始化方法ThreadLocal<String> testThreadLocal = new ThreadLocal<String>(){ public Connection initialValue(){ return "zhangsan"; }};*/public static void main(String[] args) { // 设置线程变量 testThreadLocal.set("zhangsan"); // 获取线程变量 String userName = testThreadLocal.get(); System.out.println("userName: " + userName); // 删除线程变量 testThreadLocal.remove(); userName = testThreadLocal.get(); System.out.println("userName: " + userName);}#结果输出userName: zhangsanuserName: null
public static void main(String[] args) { // 主线程 testThreadLocal.set("zhangsan"); System.out.println("userName0: " + testThreadLocal.get()); // 线程1 new Thread(() -> { testThreadLocal.set("lisi"); System.out.println("userName1: " + testThreadLocal.get()); }).start(); // 线程2 new Thread(() -> { testThreadLocal.set("wangwu"); System.out.println("userName2: " + testThreadLocal.get()); }).start();}#结果输出【线程之间变量相关隔离】userName0: zhangsanuserName1: lisiuserName2: wangwu
接下来看下set方法:
public void set(T value) { // 获取当前线程(调用方线程:主线程、线程1......) Thread t = Thread.currentThread(); // 当前线程作为key,获取对应的线程变量ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) { // 设置线程变量:key为当前定义的ThreadLocal实例的this引用,值为我们传入的数据 map.set(this, value); } else { // 第一次设置线程变量,则会创建ThreadLocalMap createMap(t, value); } }
再看下get方法:
public T get() { // 获取当前线程(调用方线程:主线程、线程1......) Thread t = Thread.currentThread(); // 当前线程作为key,获取对应的线程变量ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) { // 值最终是存在Entry对象的value属性 ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { T result = (T)e.value; return result; } } // ThreadLocalMap为空,则初始化操作 return setInitialValue();} private T setInitialValue() { // 创建ThreadLocal时可重写初始化方法 T value = initialValue(); // 获取当前线程(调用方线程:主线程、线程1......) Thread t = Thread.currentThread(); // 当前线程作为key,获取对应的线程变量ThreadLocalMap ThreadLocalMap map = getMap(t); if (map != null) { // 设置线程变量:key为当前定义的ThreadLocal实例的this引用,值为初始化方法返回的数据 map.set(this, value); } else { // 第一次设置线程变量,则会创建ThreadLocalMap createMap(t, value); } return value;}
InheritableThreadLocal:
private static InheritableThreadLocal<String> testInheritableThreadLocal = new InheritableThreadLocal<>(); public static void main(String[] args) { // 主线程 testInheritableThreadLocal.set("zhangsan"); System.out.println("userName0: " + testInheritableThreadLocal.get()); // 线程1 new Thread(() -> System.out.println("userName1: " + testInheritableThreadLocal.get())).start(); // 线程2 new Thread(() -> System.out.println("userName2: " + testInheritableThreadLocal.get())).start(); }#结果输出userName0: zhangsanuserName1: zhangsanuserName2: zhangsan
查看InheritableThreadLocal的源码:
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); }}
InheritableThreadLocal继承了ThreadLocal类型,并且重写了getMap和createMap方法,唯一的区别是:threadLocals(ThreadLocalMap类型)变成了inheritableThreadLocals(ThreadLocalMap类型)。
查看get方法:
public T get() { Thread t = Thread.currentThread(); // 注意:InheritableThreadLocal重写了getMap方法,返回inheritableThreadLocals ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { T result = (T)e.value; return result; } } return setInitialValue(); }
查看inheritableThreadLocals设置的地方,最终定位到java.lang.Thread#init方法:
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); if (inheritThreadLocals && parent.inheritableThreadLocals != null) // 将父线程inheritableThreadLocals复制给子线程inheritableThreadLocals // 此处可联想到:如果使用了线程池,而线程池中的线程是复用的,不会再次调用初始化方法 // 所以无法将父线程inheritableThreadLocals复制给子线程inheritableThreadLocals this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); this.stackSize = stackSize; tid = nextThreadID(); }
本文链接:http://www.28at.com/showinfo-26-12355-0.htmlThreadLocal和InheritableThreadLocal详解
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: API接口脱敏:如何安全地处理敏感数据?
下一篇: Java中使用正则表达式