30线程本地存储模式

没有共享,就没有伤害

1
2
3
4
5
6
7
8
9
10
11
static class SafeDateFormat {
//定义ThreadLocal变量
static final ThreadLocal<DateFormat>
tl=ThreadLocal.withInitial(()-> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

static DateFormat get(){
return tl.get();
}
}
//不同线程执行下面代码 返回的df是不同的
DateFormat df = SafeDateFormat.get();

ThreadLocal的工作原理

ThreadLocalMap,key:WeakReference,value:Value

ThreadLocal与内存泄露

线程池中线程的存活时间长,往往和程序同生共死的,则Thread持有的ThreadLocalMap一直都不会被回收。
ThreadLocalMap中的Entry对ThreadLocal是弱引用(WeakReference),所以只要ThreadLocal结束了自己的生命周期是可以被回收掉的。但是Entry中的Value却是被Entry强引用的,所以即便Value的生命周期结束了,Value也是无法被回收的,从而导致内存泄露。

解决办法:手动释放

1
2
3
4
5
6
7
8
9
10
11
12
ExecutorService es;
ThreadLocal tl;
es.execute(()->{
//ThreadLocal增加变量
tl.set(obj);
try {
// 省略业务逻辑代码
}finally {
//手动清理ThreadLocal
tl.remove();
}
});

InheritableThreadLocal与继承性

通过ThreadLocal创建的线程变量,其子线程是无法继承的(无法访问)

不建议使用:线程池中线程的创建是动态的,很容易导致继承关系错乱,若业务逻辑依赖InheritableThreadLocal,那么很可能导致业务逻辑计算错误。

问题

实际工作中,有很多平台型的技术方案都是采用ThreadLocal来传递一些上下文信息,例如Spring使用ThreadLocal来传递事务信息。我们曾经说过,异步编程已经很成熟了,那你觉得在异步场景中,是否可以使用Spring的事务管理器呢?
???