avatar

目录
threadLocal学习

ThreadLocal 学习

为线程提供一个线程私有的变量副本

ThreadLocal提供的只是一个浅拷贝,如果变量是一个引用类型,那么就要考虑它内部的状态是否会被改变,想要解决这个问题可以通过重写ThreadLocal的initialValue()函数来自己实现深拷贝

和Synchronized 的区别: 多线程一个变量

ThreadLocal:一个变量不被多个线程共享,用空间换时间

底层:

ThreadLocal中含有一个叫做ThreadLocalMap的内部类,用来存储变量副本的。key 为 ThreadLocal对象而且还使用了WeakReference,ThreadLocalMap

get方法:

通过当前线程Thread 获取线程的ThreadLocalMap(这个是线程的实例变量 存放私有数据的),如果当前线程的map为null 则setInitialValue()进行初始化 ,如果不为空 ,去取数 用当前threadLocal的变量作为key( map.getEntry(this) ) 如果没有对应的数 则把当前的threadLocal变量 加到map里面

setInitialValue:

如果线程的map为null 则CreateMap,如果不为空 则把当前的ThreadLocal 变量 对象 放到map里面

第一次创建 和新增的时候的value 默认为null

(我们可以通过重写这个函数来返回我们想要在ThreadLocal中维护的变量)

问题:值 是怎么存进去的

值是set进去的:

Code
1
2
3
4
5
6
private static final ThreadLocal contextHolder = new ThreadLocal();

// 设置数据源类型
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}

内存泄漏:

如果threadLocal变量设置为null,map中会放key为null的数,因为map在线程中 所以只要不结束 就会泄漏,

解决方法:ThreadLocalMap中的getEntry()、set()和remove()函数都会清理key为null的Entry

为什么是使用弱引用:

  • 强引用key:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的强引用,如果不手动删除,那么ThreadLocal将不会回收,产生内存泄漏。

  • 弱引用key:ThreadLocal被设置为null,由于ThreadLocalMap持有ThreadLocal的弱引用,即便不手动删除,ThreadLocal仍会被回收,ThreadLocalMap在之后调用set()、getEntry()和remove()函数时会清除所有key为null的Entry。

    为了安全地使用ThreadLocal,必须要像每次使用完锁就解锁一样,在每次使用完ThreadLocal后都要调用remove()来清理无用的Entry。

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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();
}

/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}

protected T initialValue() {
return null;
}
文章作者: 美式不加糖
文章链接: http://yoursite.com/2020/02/04/threadLocal%E5%AD%A6%E4%B9%A0/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 湖畔小屋
打赏
  • 微信
    微信
  • 支付寶
    支付寶