1. ThreadLocal (JDK版本)
1.1 ThreadLocal 概述
ThreadLocal方法及内部类.png1.2 Thread-ThreadLocal-ThreadLocalMap 关系
Thread类有成员变量threadLocals (类型是ThreadLocal.ThreadLocalMap),
也就是说每个线程有一个自己的ThreadLocalMap ,
所以每个线程往这个ThreadLocal中读写隔离的,并且是互相不会影响的。
一个ThreadLocal只能存储一个Object对象,
如果需要存储多个Object对象那么就需要多个ThreadLocal!
Thread-ThreadLocal-ThreadLocalMap.jpg
1.2.1 ThreadLocalMap
java对象的引用包括 :
强引用,软引用,弱引用,虚引用 。
因为这里涉及到弱引用,简单说明下:
弱引用也是用来描述非必需对象的,当JVM进行垃圾回收时,
无论内存是否充足,该对象仅仅被弱引用关联,那么就会被回收。
当仅有ThreadLocalMap中的Entry的key指向ThreadLocal的时候,ThreadLocal会进行回收的!
ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,
所以ThreadLocalMap 做了一些额外的回收工作。
!!!虽然做了但是也会存在内存泄漏风险
ThreadLocalMap.png
ThreadLocal防止内存泄漏做的工作-->不够.jpg
1.3 ThreadLocal的最佳实践(可以参考阿里巴巴java规范)
ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
但是Entry是强引用,那么Entry里面存储的Object,并没有办法进行回收,所以ThreadLocalMap 做了一些额外的回收工作。
#备注:
很多时候,我们都是用在线程池的场景,程序不停止,线程基本不会销毁!!!
由于线程的生命周期很长,如果我们往ThreadLocal里面set了很大很大的Object对象,
虽然set、get等等方法在特定的条件会调用进行额外的清理,
但是ThreadLocal被垃圾回收后,在ThreadLocalMap里对应的Entry的键值会变成null,
但是后续再也没有操作set、get等方法了。
#所以最佳实践
应该在我们不使用的时候,主动调用remove方法进行清理。
try {
// 其它业务逻辑
} finally {
threadLocal对象.remove();
}
ThreadLocal最佳实践.jpg
1.4 ThreadLocal用在什么地方?
#应用场景概述
>> 保存线程上下文信息,在任意需要的地方可以获取!!!
>> 线程安全的,避免某些情况需要考虑线程安全必须同步带来的性能损失!
#例如
由于ThreadLocal的特性,同一线程在某地方进行设置,在随后的任意地方都可以获取到。
从而可以用来保存线程上下文信息。
常用的比如每个请求怎么把一串后续关联起来,就可以用ThreadLocal进行set,
在后续的任意需要记录日志的方法里面进行get获取到请求id,从而把整个请求串起来。
还有比如Spring的事务管理,用ThreadLocal存储Connection,
从而各个DAO可以获取同一Connection,可以进行事务回滚,提交等操作。
1.5 ThreadLocal应用示例
1.5.1 用于存储线程信息
package com.zy.tools.undefined.concurrent.threadlocal;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
public class ThreadLocalDemo01 {
private static final ExecutorService executor = Executors.newCachedThreadPool();
private static ThreadLocal<String> threadLocal = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(4);
for (int i = 1; i < 5; i++) {
int finalI = i;
executor.submit(() -> {
try {
threadLocal.set(Thread.currentThread().getName() + " ---> " + finalI);
System.out.println(threadLocal.get());
countDownLatch.countDown();
} finally {
threadLocal.remove();
}
});
}
countDownLatch.await(5L, TimeUnit.SECONDS);
executor.shutdown();
}
}
2. FastThreadLocal (Netty版本)
参考资源
https://mp.weixin.qq.com/s/yBLIbWs7bA0rjYj3Ypxd9g (JDK ThreadLocal)
网友评论