[关闭]
@yulongsun 2018-09-20T13:40:03.000000Z 字数 2032 阅读 752

ThreadLocal剖析

Java知识点


  1. ThreadLocal是什么?ThreadLocal有什么好处?
  2. ThreadLocal会产生内存泄漏吗?
  3. 当存储Value的时候发生冲突怎么办?
  4. 为什么在ThreadLocalMap中弱引用Entry呢?

内部结构

关键类

1. ThreadLocal#set()

  1. public void set(T value) {
  2. Thread t = Thread.currentThread();
  3. //重要:根据线程获取Map
  4. ThreadLocalMap map = getMap(t);
  5. if (map != null)
  6. map.set(this, value);
  7. else
  8. createMap(t, value);
  9. }

根据当前线程获取Map,如果Map为空,则createMap().

  1. ThreadLocalMap getMap(Thread t) {
  2. return t.threadLocals;//返回一个**线程绑定**的ThreadLocalMap
  3. }
  1. void createMap(Thread t, T firstValue) {
  2. t.threadLocals = new ThreadLocalMap(this, firstValue);
  3. }

可以看出,其实Thread本身就内置了一个ThreadLocalMap。

那么接下来的重点就是看ThreadLocalMap如何初始化了。

1.1 创建ThreadLocalMap过程(初始化过程)

  1. ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
  2. //初始化一个长度=16的对象数组。Entry extends WeakReference
  3. table = new Entry[INITIAL_CAPACITY];
  4. //确定Hash值
  5. int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
  6. //设值
  7. table[i] = new Entry(firstKey, firstValue);
  8. size = 1;
  9. setThreshold(INITIAL_CAPACITY);
  10. }

1.2 构造函数,创建Entry并设值

(重要!所以用截图)
image_1cnrgn0mi1ceqoch1gprpkv1i0738.png-100kB

拓展:为什么在ThreadLocalMap中弱引用Entry呢?

1.3 如何设值呢?

麻烦点:如果Hash冲突了怎么办呢?

  1. private void set(ThreadLocal<?> key, Object value) {
  2. Entry[] tab = table;
  3. int len = tab.length;
  4. int i = key.threadLocalHashCode & (len-1);
  5. for (Entry e = tab[i];
  6. e != null;
  7. e = tab[i = nextIndex(i, len)]) {
  8. ThreadLocal<?> k = e.get();
  9. //
  10. if (k == key) {
  11. e.value = value;
  12. return;
  13. }
  14. if (k == null) {
  15. replaceStaleEntry(key, value, i);
  16. return;
  17. }
  18. }
  19. tab[i] = new Entry(key, value);
  20. int sz = ++size;
  21. if (!cleanSomeSlots(i, sz) && sz >= threshold)
  22. rehash();
  23. }

解决方法:
ThreadLocalMap解决Hash冲突的方式就是简单的步长加1或减1,寻找下一个相邻的位置。

2. ThreadLocal#get()

  1. public T get() {
  2. Thread t = Thread.currentThread();
  3. ThreadLocalMap map = getMap(t);
  4. if (map != null) {
  5. ThreadLocalMap.Entry e = map.getEntry(this);
  6. if (e != null) {
  7. @SuppressWarnings("unchecked")
  8. T result = (T)e.value;
  9. return result;
  10. }
  11. }
  12. return setInitialValue();
  13. }

应用场景

数据库连接、Session管理

参考
1. https://www.jianshu.com/p/98b68c97df9b

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注