ThreadLocal源码分析
来源:互联网 发布:php时间戳精确到毫秒 编辑:程序博客网 时间:2024/06/16 07:05
ThreadLocal这个类给线程提供了一个本地变量,这个变量是该线程自己拥有的。在该线程存活和ThreadLocal实例能访问的时候,保存了对这个变量副本的引用.当线程消失的时候,所有的本地实例都会被GC。建议ThreadLocal最好是 private static 修饰的成员。
get方法:
ThreadLocalMap结构如下:
set方法:
如果计算后的坐标获取到的entry为null,就new一个Entry对象并保存进去,然后调用cleanSomeSlots()对table进行清理,如果没有任何Entry被清理,并且数组的size超过了阈值,就会调用rehash()方法。
cleanSomeSlots()中会调用expungeStaleEntry清理不用的Entry。rehash则会调用expungeStaleEntries()方法清理所有不用的Entry:
public class ThreadLocal<T> { private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }ThreadLocals 解决Hash 冲突使用线性探测的方法。其中key为ThreadLocal对象,因为Thread类中的threadLocals是个ThreadLocalMap对象,意味一个Thread中可以存放多个ThreadLocal对象。因此用threadLocalHashCode来区分是哪个ThreadLocal类型。
get方法:
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(); }返回当前线程的threadLocal变量,如果这个变量对当前线程没有值,则它调用前面介绍的initialValue方法获取初始值。
ThreadLocalMap getMap(Thread t) { return t.threadLocals; }Thread中threadLocals定义:
ThreadLocal.ThreadLocalMap threadLocals = null;
ThreadLocalMap结构如下:
static class ThreadLocalMap { static class Entry extends WeakReference<ThreadLocal<?>> { /** The value associated with this ThreadLocal. */ Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } private static final int INITIAL_CAPACITY = 16; private Entry[] table; private int size = 0; private int threshold; // Default to 0 private void setThreshold(int len) { threshold = len * 2 / 3; } private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); } 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数组,Entry是继承WeakReference。ThreadLocalMap的getEntry方法:
private Entry getEntry(ThreadLocal<?> key) { int i = key.threadLocalHashCode & (table.length - 1); Entry e = table[i]; if (e != null && e.get() == key) return e; else return getEntryAfterMiss(key, i, e); }先结合threadLocalHashCode与table.length – 1的值确定该ThreadLocal在ThreadLocalMap的Entry数组下标位置。然后根据下标如果能在table找到直接返回,否则调用getEntryAfterMiss:
private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal<?> k = e.get(); if (k == key) return e; if (k == null) expungeStaleEntry(i); else i = nextIndex(i, len); e = tab[i]; } return null; }解释下e.get() == null表示这个key引用被垃圾回收了,因此需要调用expungeStaleEntry方法从数组里删除该Entry;如果其它情况需要向后找下一个Entry,因为采用的是线性探测法解决冲突的。
set方法:
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的set方法如下:
private void set(ThreadLocal<?> key, Object value) { Entry[] tab = table; int len = tab.length; int i = key.threadLocalHashCode & (len-1); for (Entry e = tab[i]; e != null; e = tab[i = nextIndex(i, len)]) { ThreadLocal<?> k = e.get(); if (k == key) { e.value = value; return; } if (k == null) { replaceStaleEntry(key, value, i); return; } } tab[i] = new Entry(key, value); int sz = ++size; if (!cleanSomeSlots(i, sz) && sz >= threshold) rehash(); }for循环中是根据计算得出的下标在table中找Entry,当Entry不为空时,如果是同一个对象,k == key,直接替换Entry里面的value值;如果k为null,说明k被回收了,重新放入该位置;否则向后继续找Entry,直到Entry为空。
如果计算后的坐标获取到的entry为null,就new一个Entry对象并保存进去,然后调用cleanSomeSlots()对table进行清理,如果没有任何Entry被清理,并且数组的size超过了阈值,就会调用rehash()方法。
cleanSomeSlots()中会调用expungeStaleEntry清理不用的Entry。rehash则会调用expungeStaleEntries()方法清理所有不用的Entry:
private void rehash() { expungeStaleEntries(); // Use lower threshold for doubling to avoid hysteresis if (size >= threshold - threshold / 4) resize(); }
阅读全文
0 0
- ThreadLocal源码分析
- Threadlocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析解密
- ThreadLocal源码分析
- java-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- android-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- ThreadLocal源码简单分析
- 激发偶尔;未决犯;
- SGU
- YTU OJ 2994: 凑算式 (蓝桥杯题目)
- 自己动手写操作系统时遇到的关于VGA显示的疑问
- [NOIP2017模拟]弹球
- ThreadLocal源码分析
- 20171019 JAVA Spring框架——事务管理方式搭建一个小的项目
- io流之fileoutputstream
- 实战Spring事务传播性与隔离性
- 155. Min Stack
- java提取字符串中的字母数字
- java多线程详解介绍线程池使用
- Implement strStr()--LeetCode
- 关于Linux的进程通信中信号的函数理解