threadLocal 为线程私有,使用方式
HashMap hashMap = new HashMap();
hashMap.put("threadName",Thread.currentThread().getName());
ThreadLocal local = new ThreadLocal();
local.set(hashMap);
System.out.println(((HashMap)local.get()).get("threadName"));
源码 分析
public class Thread implements Runnable {
// thread 类属性存 ThreadMap 内存地址
...
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
...
}
// threadlcoal 在set value
public void set(T value) {
Thread t = Thread.currentThread();
// 获取当前线程 ThreadLocalMap
// ThreadLocalMap map = t.threadLocals;
ThreadLocalMap map = getMap(t);
// map 不为空 说明当前线程有指定的 threadlocalMap 对象,
if (map != null)
// this 为当前对象 threadLocal
map.set(this, value);
else
// 为空则创建 ThreadLocalMap
createMap(t, value);
}
// t.threadLocals = new ThreadLocalMap(this, firstValue);
// threadLocalMap 采用 entry[] 存value key为 threadLocal
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);
}
entry.java 类 extends WeakReference<ThreadLocal<?>> 为弱引用,弱引用 jvm 在gc时就会被清除。
key 为弱引用,如果threadLocal 对象失去了 强引用( threadLocal = null;) 单独剩余 弱引用 在下次 GC 时 threadLocal 对象就会被清除,则 entry 对象 key 也就为 null 了。
ThreadLocalMap 根据 key 取Value,key 为空 value 也就是垃圾对象了,如果线程长时间存活 value 就一直不能被回收。
每次在 get、set 方法时 也会清除 key为空的 entry 对象,释放无效对象。
static class Entry extends WeakReference<ThreadLocal<?>> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
扩展下 java 四种引用类型:
* java 四种引用类型
* 强、软、弱、虚引用
* java 默认强引用
* 软引用 :SoftReference<byte> m = new SoftReference(new byte(1024*1024*10));
* 获取软引用对象字节数组 m.get();
* 软引用 在内存空间不足时,GC优先处理软引用。
* 使用场景 【缓存】
* 弱引用:WeakReference<M> m = new WeakReference<>(new M());
* 获取弱引用对象 m.get();
* 弱引用 gc执行时发现弱引用,就会清除
* 虚引用 phantomReferebce
* 使用场景:跟踪对象垃圾被回收的活动,虚引用必须和引用队列 (ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。你声明虚引用的时候是要传入一个queue的。当你的虚引用所引用的对象已经执行完finalize函数的时候,就会把对象加到queue里面。你可以通过判断queue里面是不是有对象来判断你的对象是不是要被回收了