ThreadLocal 使每一个线程有独立的副本:它 提供了线程内存储变量的能力,这些变量不同之处在于每一个线程读取的变量是对应的互相独立的。通过get和set方法就可以得到当前线程对应的值。
在多线程并发情况下,有一个共享变量,不同线程设置不同值后,各线程只获取自己设置的值
public class ThreadLocalTest { private static ThreadLocal<Integer> threadLocal = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 1; } }; /** * 测试线程,线程的工作是将ThreadLocal变量的值变化,并写回,看看线程之间是否会互相影响 */ private static class ThreadInfo extends Thread{ int num; public ThreadInfo(int num){ this.num = num; } @Override public void run() { int tl = threadLocal.get(); tl += num; threadLocal.set(tl); System.out.println(Thread.currentThread().getName()+"---threadLocal.get():"+threadLocal.get()); } } public static void main(String[] args) { int times = 5; Thread[] threads = new Thread[times]; for (int i = 0; i < times; i++) { threads[i] = new ThreadInfo(i); } for (int i = 0; i < times; i++) { threads[i].start(); } } }
每一个线程获取的ThreadLocal都是独立的。
public class NoThreadLocal { static int noThreadLocal = 1; private static class ThreadInfo extends Thread{ public int num; public ThreadInfo(int num){ this.num = num; } @Override public void run() { noThreadLocal = noThreadLocal + num; System.out.println( Thread.currentThread().getName()+"---:"+noThreadLocal); } } public static void main(String[] args) { int times = 5; ThreadInfo[] threads = new ThreadInfo[times]; for (int i = 0; i < times; i++) { threads[i] = new ThreadInfo(i); } for (int i = 0; i < times; i++) { threads[i].start(); } } }
源码注释:将此线程局部变量的当前线程副本设置为指定值。大多数子类无需重写此方法,只需依赖{@link#initialValue}方法来设置线程局部变量的值。
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); }
如果getMap方法获取的ThreadLocalMap类型变量map不等于null,则以当前ThreadLocal实例对象为key,传入的value值为value存到这个ThreadLocalMap中,需要注意的是在实际存储的时候,key使用的是ThreadLocal的弱引用。
如果getMap方法获取的ThreadLocalMap类型变量map等于null,则调用createMap方法创建一个ThreadLocalMap实例对象,并以当前ThreadLocal实例对象为key,传入的value值为value存到这个ThreadLocalMap中。
看到这里就会明白,使用ThreadLocal时,每个线程维护一个ThreadLocalMap映射表,映射表的key是ThreadLocal实例,并且使用的是ThreadLocal的弱引用 ,value是具体需要存储的Object。
源码注释:返回此线程局部变量的当前线程副本中的值。如果变量没有当前线程的值,则首先将其初始化为调用{@link#initialValue}方法返回的值。
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
源码注释:此哈希映射中的条目使用它的主ref字段作为键(它总是线程本地对象)。注意空键(即entry.get()==null)表示不再引用密钥,因此条目可以从表中删除。这些条目被提及作为下面代码中的“陈旧条目”
static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } }
源码注释:用于建立初始值的set()的变量。取而代之以防用户重写set()方法
private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
参考网址:
https://www.jianshu.com/p/3c5d7f09dfbd
原文:https://www.cnblogs.com/mjtabu/p/12723554.html