在并发编程中ThreadLocal是一个特殊并且比较重要的点,在很多框架中都有用到它并且它的设计也是相当巧妙使用起来也是相当简便,所以本篇文章将从源码及使用角度介绍ThreadLocal
ThreadLocal简介
首先我们需要明确一点,ThreadLocal的设计初衷是为了解决不同线程间使用共享变量的隔离问题而不是解决多线程共同修改同一个共享变量的问题,ThreadLocal是将要操作的共享变量在每个线程中保存一份,操作该共享变量时各个线程之间互不影响,要解决多线程间修改同一个共享变量还是要通过加锁或CAS来实现。 下图展示了他们两者的区别。
如上图虽然可能不那么恰当,但针对库存每个线程对它-1其他线程需要得到他修改后的最新数据再去更改,而针对购物车假定我们只有一个购物车多个线程同时去添加一个购物车肯定是不行的,这个时候我们就需要把购物车在每个线程都保存一份各自去操作各自的购物车
ThreadLocal使用
虽然ThreadLocal设计上相对复杂但使用上比较简单,常用的方法包括set()设置值 get()获取值 remove()移除值,以下仅为DEMO并不具备实际功能
注意:当在线程池中使用ThreadLocal时使用完一定要及时remove,不然线程池中的核心线程不会被销毁当前线程中的值可能会影响下次线程的使用。
public class ThreadLocalDomo {
private static ThreadLocal<String> shoppingCar=new ThreadLocal<String>();
@Autowired
private ThreadPool threadPool;
public void demo(){
threadPool.fixdPool().submit(() -> {
shoppingCar.set("redis开发与运维,高性能Mysql");
shoppingCar.get();
shoppingCar.remove();
});
threadPool.fixdPool().submit(() -> {
shoppingCar.set("java并发编程艺术,大话设计模式");
shoppingCar.get();
shoppingCar.remove();
});
}
}
源码分析
在分析源码前我们先看一张图有一个大概了解,这是Thread类中threadLocalMap的结构图,在Thread类中会有一个ThreadLocalMap对象,ThreadLocalMap中保存了一个entry类型的数组保存这个线程中所有的ThreadLocal,每一个entry是一个键值对key为ThreadLocal的弱引用,value为这个ThreadLocal的值。
下面我们从threadLocal的set方法为入口来看一下它的一个整体流程
使用场景
1.替代session全局保存用户信息
2.并发情况下操作作用域为线程的共享变量