ThreadLocal设计思想

2020-02-16  本文已影响0人  手打丸子

之前分享过TheadLocal的创建销毁原则,并且使用代码进行了测试ThreadLocal内存泄露
使用ThreadLocal的目的:
1.又希望并发安全,又不想使用锁;
2.线程间隔离,且希望线程内任务获取的是同一个对象,如spring中事务模块将数据库连接放在ThreadLocal中;

那怎么使用才是比较安全的使用方式呢
根据生命周期划分,主要分为三种情况

1.与Thread生命周期相同
一般适用于线程不安全的工具类,比如SimpleDateFormat;
或者数据库连接之类的,在spring中有使用,不仅仅保证了并发安全,也保证了同一个线程拿到的同一个connection,来保证事务性;
放在

//使用ThreadLocal代替原来的new SimpleDateFormat
    private static final ThreadLocal<SimpleDateFormat> dateFormatter = new   ThreadLocal<SimpleDateFormat>(){
        //放在initialValue中会在首次get的时候初始化
        @Override
        protected SimpleDateFormat initialValue() {
            return  new SimpleDateFormat("yyyy-MM-dd");
        }
    };

//使用时
dateFormatter.get().format(new Date());

2.与task生命周期相同
这里有两种使用方式

一种是嵌套方式

   private static final ThreadLocal<Object> threadLocal = new   ThreadLocal<Object>();

try{
  threadLocal.set(new Object());
  //这里做真的业务
  doBiz();
}finally{
  threadLocal.remove();
}

当然,不嵌套也是可以的,需要有明确的业务入口

   private static final ThreadLocal<Object> threadLocal = new   ThreadLocal<Object>();

  //在业务开始前完成ThreadLocal的设置
  threadLocal.set(new Object());
  doBiz();

3.小于task生命周期
这种情况只能使用嵌套方式
但是由于线程内任何地方都可以设置该ThreadLocal
所以,一定要封锁住set的权限,只能在一个地方set,如果那里都能访问到并且set,就乱套了
当然,你有胆量的话,能整理清楚复杂的业务逻辑,保证变量不出问题,就大胆随意用吧

  public class BusinessHandler {

        private static ThreadLocal<String> name = new ThreadLocal<>();

        private static void setName(String newName){
            name.set(newName);
        }

        public static String getName(){
            return name.get();
        }

        public void handle(){
            String thisName = "new name";
            setName(thisName);
            doBiz();
        } 
}

//在其他地方使用该ThreadLocal
public void doBiz() {
            // use name
            BusinessHandler.getName();
        }
上一篇 下一篇

猜你喜欢

热点阅读