zcpHappy 2020-06-16
public static void main(String[] args) { ThreadLocal<Integer> threadLocal = new ThreadLocal<>(); threadLocal.set(999); // 模拟3个线程 for (int i=0; i<3; i++) { new Thread(()-> { for (int j = 0; j<2000; j++) { if (null==threadLocal.get()) { threadLocal.set(1); } else { threadLocal.set(threadLocal.get()+1); } } System.out.println(Thread.currentThread().getName() + " " + threadLocal.get()); }).start(); } System.out.println(Thread.currentThread().getName() + " " + threadLocal.get()); }
输出结果:
main 999 Thread-0 2000 Thread-1 2000 Thread-2 2000
上述示例说明:线程与线程之间相互隔离,且线程安全。ThreadLocal作用域为当前线程
// set方法一般都是set(key, value),因为ThreadLocalMap使用了当前线程作为key,所以省略了,get()方法也一样。 public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; // 这个变量在Thread类中,ThreadLocal.ThreadLocalMap threadLocals = null; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
首次在调用 set方法时,会执行createMap,在createMap方法中又会创建一个ThreadLocalMap对象,我们再来看一下ThreadLocalMap这个构造方法
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) { table = new Entry[INITIAL_CAPACITY]; int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1); table[i] = new Entry(firstKey, firstValue); size = 1; setThreshold(INITIAL_CAPACITY); }
通过构造方法,我们可以看出ThreadLocal底层使用的就是HashMap结构
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table; }
public static void main(String[] args) throws InterruptedException { WeakHashMap<String, String> weakMap = new WeakHashMap<String, String>(); String key = new String("1"); String key2 = "2"; weakMap.put(key, "test"); weakMap.put(key2, "test2"); System.out.println(weakMap); // {1=test, 2=test2} key = null; key2 = null; // 不会被回收 System.gc(); System.out.println(weakMap); // {2=test2} }
我们可以看出WeakHashMap针对key作了回收,而在整个map中并没有真正的回收此对象。在ThreadLocal中,它使用当前线程作为key的,如果线程生命周期结束后,即这个key以及对就的value都应该被GC掉