大家好,我是徒手敲代码。
今天来介绍一下ThreadLocal。
专业解释:ThreadLocal是为了确保线程安全,提供线程间数据隔离而设计的一种机制。它允许每个线程拥有各自独立的变量副本,即使变量名相同,不同线程之间的变量值也不会相互影响。底层基于一个内部类ThreadLocalMap(一个弱引用的Entry数组),数组当中,以ThreadLocal实例为 key,存储任何类型的对象作为 value。多线程环境下,帮助每个线程维持独有的任务执行环境,或者上下文信息,比如用户会话、事务 id 等等。
通俗一点,假设商场的客人就是一个个的线程,那么放在储物柜的东西,就是每个线程各自的资源。客人 A 不能去拿客人 B 的东西,就像线程 1 不能去访问线程 2 的数据一样。
既然是每个线程都保存一份,那么如果线程数一旦多了起来,或者保存的数据占用空间很大,而且用完之后没有及时释放,肯定会造成严重的内存泄漏。
针对这个问题,threadLocal主要采用弱引用 + 手动调用remove()方法的思路来解决。内存泄漏主要是因为用完的对象没有被及时地进行垃圾回收,那么我们在使用它的过程中,一旦这个threadLocal对应的对象没有用了,那么就要及时调用remove()方法,不要有半点犹豫,真正做到用完即弃。
下面写一个使用threadLocal的演示Demo:
public class ThreadLocalExample {
// 静态ThreadLocal变量,用于演示线程隔离
private static final ThreadLocal<Integer> threadLocal = new ThreadLocal<>();
public static void main(String[] args) {
System.out.println("线程开始执行。。。");
// 创建并启动两个线程
Thread thread1 = new Thread(new Worker(), "Thread-1");
Thread thread2 = new Thread(new Worker(), "Thread-2");
thread1.start();
thread2.start();
// 确保两个线程执行完毕再结束程序(非必须,仅为观察输出)
try {
thread1.join();
thread2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("所有线程执行完毕");
}
static class Worker implements Runnable {
@Override
public void run() {
// 每个线程生成一个随机数并存储到各自的ThreadLocal中
int randomValue = new Random().nextInt(100);
threadLocal.set(randomValue);
// 打印当前线程名和其对应的ThreadLocal中的值,体现线程隔离
System.out.println("线程: " + Thread.currentThread().getName() +
", 随机数: " + threadLocal.get());
// 模拟其他操作后更新ThreadLocal的值
try {
Thread.sleep(500); // 减少等待时间以便更快地观察输出
} catch (InterruptedException e) {
e.printStackTrace();
}
// 更新ThreadLocal的值并再次打印,证明是线程独有的
randomValue = new Random().nextInt(100);
threadLocal.set(randomValue);
System.out.println("线程: " + Thread.currentThread().getName() +
", 更新的随机数: " + threadLocal.get());
// 使用remove防止内存泄漏,特别是在不再需要ThreadLocal变量时
threadLocal.remove();
}
}
}
今天的分享到这里结束了。
关注公众号“徒手敲代码”,免费领取腾讯大佬推荐的Java电子书!