ThreadLocal源码分析
来源:互联网 发布:安卓玩java游戏 编辑:程序博客网 时间:2024/06/07 03:12
ThreadLocal是java多线程编程中非常重要的一个类。ThreadLocal存放的变量只能由相应的线程进行访问,即ThreadLocal为每个线程存放一个变量的副本。
下面对ThreadLocal进行源码分析
Thread 类
查看Thread类的源代码,可以看到Thread类中有个
ThreadLocal.ThreadLocalMap threadLocals = null;
此变量没有声明为private,而是使用了默认的类型friendly,即同一个包下下的类可以看到。
其实 线程本地变量就存储在threadLocals map中。
ThreadLocal 类
public class ThreadLocal<T> { /** * ThreadLocals 解决Hash 冲突使用线性探测的方法。 * 其中key为ThreadLocal对象。因为Thread类中的 threadLocals是个map对象。 * 意外这一个Thread中可以存放多个ThreadLocal对象。所以Key为ThreadLocal,value为需要存放的值。 * 把threadLocalHashCode声明为final,所以可以作为 ThreadLocalMap中的key,保持不变。 * 调用nextHashCode()使得每次把共享的类变量值+1; */ private final int threadLocalHashCode = nextHashCode(); /** * nextHashCode声明为static,代表类变量。默认初始值为 0。 * 使用原子整数类作为下一个hashcode值。由于是个类变量,所以当jvm把ThreadLocal加载到内存中时。 * nextHashCode只有一份,是线程共享的。 */ private static AtomicInteger nextHashCode = new AtomicInteger(); /** *由于采用线性探测,所以代表下一个值在当前值得hash增长。 */ private static final int HASH_INCREMENT = 0x61c88647; /** * 返回一下hashcode */ private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }
initialValue()方法
/** *这个方法返回当前线程threadLocal的初始变量值。 *这个方法的调用出现在ThreadLocal调用get()方法,然后之前没有调用ThreadLocal的set()方法。 *这个方法被当前线程调用一次或者调用多次。当调用ThreadLocal的remove()方法后,可能会再次调用此方法。 *这个方法默认返回Null,如果程序员想让它返回一个初始值,通过一个匿名内部类重写此方法。 *如: ThreadLocal<Integer> local = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 0; } }; */ protected T initialValue() { return null; }
get()方法
/** * 返回当前线程的threadLocal变量的拷贝值。 * 如果这个变量对当前线程没有值,则它调用前面介绍的initialValue方法获取初始值。 */ public T get() { Thread t = Thread.currentThread(); //依据当前线程获取ThreadLocalMap /** * 获取Thread对象的threadLocals属性 * ThreadLocalMap getMap(Thread t) { return t.threadLocals; } */ ThreadLocalMap map = getMap(t); if (map != null) { /** *由于一个thread对象可以存放多个ThreadLocal变量,因此使用ThreadLocal作为key值。 */ ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); }
ThreadLocalMap数据结构
static class ThreadLocalMap { /** * 这个entry继承WeakReference,为了避免当内存不够用被回收。 * 注意null keys(如:entry.get()==null)意外这这个Key不再引用,因此这个entry可以从这个表中被移除。 * */ static class Entry extends WeakReference<ThreadLocal<?>> { Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; } } /** * table的初始化值,必须是2的幂。默认是16 */ private static final int INITIAL_CAPACITY = 16; /** * 这个表可以动态扩展 * 表的长度必须是2的幂 */ private Entry[] table; /** * 表中的元素的数量. */ private int size = 0; /** * 当size大于threshode时,就需要进行扩容。类似于加载因子 */ private int threshold; // Default to 0 /** * threadHold的设置值方法 */ private void setThreshold(int len) { threshold = len * 2 / 3; } ...
getEntry(ThreadLocal key ) 方法
private Entry getEntry(ThreadLocal<?> key) { //获取hash 值code 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); } private Entry getEntryAfterMiss(ThreadLocal<?> key, int i, Entry e) { Entry[] tab = table; int len = tab.length; while (e != null) { ThreadLocal<?> k = e.get(); //由于key为this对象。因此采用比较内存地址的方式 if (k == key) return e; //如果key为null,则引用被垃圾回收,需要从表里删除 if (k == null) expungeStaleEntry(i); else //把i值加1再做判断,直到找到对应的key值 i = nextIndex(i, len); e = tab[i]; } return null; }
expungeStaleEntry()源码分析
由于Key为WeakReference,因此当key被垃圾回收时,需要把entry从table中移除。并重新rehash整个数组
nextIndex函数的定义如下:
private static int nextIndex(int i, int len) { return ((i + 1 < len) ? i + 1 : 0); }
在重新rehash的过程中,如果遇到key==null,则把value设置为null。
否则如果key != null,则hash,如果对应的hashcode !==i,则把tab[i] = null,并线性探测tab[h],直到tab[h]==null,并把此元素放入到tab[h]中。
private int expungeStaleEntry(int staleSlot) { Entry[] tab = table; int len = tab.length; // expunge entry at staleSlot tab[staleSlot].value = null; tab[staleSlot] = null; size--; // Rehash until we encounter null Entry e; int i; for (i = nextIndex(staleSlot, len); (e = tab[i]) != null; i = nextIndex(i, len)) { ThreadLocal<?> k = e.get(); if (k == null) { e.value = null; tab[i] = null; size--; } else { int h = k.threadLocalHashCode & (len - 1); if (h != i) { tab[i] = null; while (tab[h] != null) h = nextIndex(h, len); tab[h] = e; } } } return i; }
阅读全文
0 0
- ThreadLocal源码分析
- Threadlocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析解密
- ThreadLocal源码分析
- java-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- android-----ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal源码分析
- ThreadLocal的源码分析
- ThreadLocal源码简单分析
- Spark Streaming中的操作函数
- maven(一)pom文件讲解
- zhx's contest
- JAVA企业面试题精选 Java基础 1-10
- 选课时间(题目已修改,注意读题)
- ThreadLocal源码分析
- JAVA中的三大集合框架
- OpenGL中的光照
- 文章标题
- Android系列之实现ViewFlipper图片动画滑动
- 51 《格鲁夫给经理人的第一课》 -豆瓣评分8.8
- [译]机器学习简史
- 正则表达式
- 羚羊应用系统开发板开发笔记(1)简单的实现播放器的快进,后退,暂停播放歌曲。