结构

适用场景
需要是当前线程资源持有的
- 多个应用需要访问同一个线程持有的变量
- 比如可以通过 ThreadLoalMap 拿用户数据
需要线程资源保持一致性
- 比如 jdbc 控制同一个线程的事务中的数据库连接是同一个连接

线程安全
- 避免线程不安全,因为 ThreadLocal 是当前线程才持有
分布式计算
- 可以将需要计算的部分分分给多个线程计算,然后汇集计算结果
注意事项
- tomcat 会重用线程
- ThreadLocal 会被重用,如果是存储当前用户,需要先干掉
API
简单使用
class TL {public static ThreadLocal<Integer> local = new ThreadLocal<Integer>(){@Overrideprotected Integer initialValue() {System.out.println("initial value!");return 1;}};public static void main(String[] args) {// 会初始化值local.get();// 不会初始化值local.get();// 干掉 locallocal.remove();// 会初始化值local.get();}}
减少同步/伪分布式
- 比如访问接口的自增一计算
- 如果要用
synchroinized来修饰共享变量,会造成 qps 减低- 当然可以用
Atomic类来搞,这里只是说一下如何减少同步
- 当然可以用
- 可以统计各个线程的访问当前接口的访问量

@RestController@RequestMapping("/lo")public class TreadLocalController {/*** 保存各个线程的 Val* 而各个 Val 保存是当前线程的 ThreadLocal 的值*/static HashSet<Val<Integer>> saveSet = new HashSet<>();/*** 避免线程不安全* 由于在 initalValue() 中才会使用到,所以被执行的次数是 <线程总数>*/private synchronized void setValue(Val<Integer> val) {saveSet.add(val);}/*** 当前线程 ThreadLocal*/private ThreadLocal<Val<Integer>> threadLocal = new ThreadLocal<Val<Integer>>() {@Overrideprotected Val<Integer> initialValue() {System.out.println(Thread.currentThread().getName() + "- 初始化了" );// 由于只能拿当前线程的值,干脆把数据存到另一个结构中,引用扔进 setVal<Integer> val = new Val<>();val.set(0);// HashSet 线程不安全setValue(val);return val;}};@RequestMapping("/add")public String add() {// 给 threadLocal 自增一Val<Integer> cur = threadLocal.get();cur.set(cur.get() + 1);return "success";}@RequestMapping("/get")public String get() {Integer sum = 0;for (Val<Integer> val : saveSet) {sum += val.get();}String str = "总数: " + saveSet.size() + ": 值: " + sum;return str;}}/*** 存储 ThreadLocal 的值,因为返回 ThreadLocal 本身有点难度* @param <T>*/class Val<T> {private T t;public void set(T t) {this.t = t;}public T get() {return t;}}
