Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(三)

③. ThreadLocal 解决日期格式乱码问题


/**
 * 在对一些业务日志写入数据库的时候,日期调用了sdf的静态,导致了会报错或者日期乱了
 * */
public class ThreadLocalDataUtils {

    public static SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     解决方案一:加入synchronized,用时间换空间,效率低
    */
    /**
     如果不加会导致线程安全问题,SimpleDateFormat类内部有一个Calendar对象引用,
     SimpleDateFormat相关的日期信息,例如sdf.parse(dateStr),sdf.format(date)
     诸如此类的方法参数传入的日期相关String,Date等等, 都是交由Calendar引用来储存的.
     这样就会导致一个问题如果你的SimpleDateFormat是个static的,那么多个thread之间
     就会共享这个SimpleDateFormat,同时也是共享这个Calendar引用(相当于买票案列)
    */
    //public static synchronized Date parse(String stringDate) throws ParseException {
    public static  Date parse(String stringDate) throws ParseException {
        System.out.println(sdf.parse(stringDate));
        return sdf.parse(stringDate);
    }

    /***
     * 解决方案二:使用ThreadLocal,用空间换时间,效率高
     * ThreadLocal中变量副本会人手一份,每次使用完了threadLocal后都要将资源进行释放的处理
     */
    public static final ThreadLocal<SimpleDateFormat>sdfThreadLocal=
            ThreadLocal.withInitial(()->new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
    public static  Date parseByThreadLocal(String stringDate) throws ParseException {
        return sdfThreadLocal.get().parse(stringDate);
    }
    //3 DateTimeFormatter 代替 SimpleDateFormat
    public static final DateTimeFormatter DATE_TIME_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    public static String formatForDateTime(LocalDateTime localDateTime) {
        return DATE_TIME_FORMAT.format(localDateTime);
    }

    public static LocalDateTime parseForDateTime(String dateString) {
        return LocalDateTime.parse(dateString,DATE_TIME_FORMAT);
    }

    public static void main(String[] args) throws Exception{
        for (int i = 1; i <=3; i++) {
            new Thread(()->{
                try {
                   //ThreadLocalDataUtils.parse("2021-03-30 11:20:30");
                   //System.out.println(ThreadLocalDataUtils.parseByThreadLocal("2021-03-30 11:20:30"));
                   System.out.println(ThreadLocalDataUtils.parseForDateTime("2021-03-30 11:20:30"));
                   // System.out.println(ThreadLocalDataUtils.formatForDateTime(LocalDateTime.now()));
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    ThreadLocalDataUtils.sdfThreadLocal.remove();
                }
            },String.valueOf(i)).start();
        }
    }
}


④. 阿里规范怎么说的?


Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(三)


③. ThreadLocal源码分析


①. Thread|ThreadLocal|ThreadLocalMap关系


  • ①. Thread和ThreadLocal


Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(三)


②. ThreadLocal和ThreadLocalMap


Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(三)


③. All三者总概括


Thread类中有一个ThreadLocal.ThreadLocalMap threadLocals = null的变量,这个ThreadLocal相当于是Thread类和ThreadLocalMap的桥梁,在ThreadLocal中有静态内部类ThreadLocalMap,ThreadLocalMap中有Entry数组


当我们为threadLocal变量赋值,实际上就是以当前threadLocal实例为key,值为value的Entry往这个threadLocalMap中存放


t.threadLocals = new ThreadLocalMap(this, firstValue) 如下这行代码,可以知道每个线程都会创建一个ThreadLocalMap对象,每个线程都有自己的变量副本


Juc17_ThreadLocal概述、解决SimpleDateFormat出现的异常、内存泄漏、弱引用、remove方法(三)

//核心代码说明
public void set(T value) {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null)
        map.set(this, value);
    else
        createMap(t, value);
}
void createMap(Thread t, T firstValue) {
   t.threadLocals = new ThreadLocalMap(this, firstValue);
}
ThreadLocalMap(ThreadLocal<?> firstKey, Object firstValue) {
    table = new Entry[INITIAL_CAPACITY];
    int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
    table[i] = new Entry(firstKey, firstValue);
    size = 1;
    setThreshold(INITIAL_CAPACITY);
}




上一篇:SQL优化常用方法5


下一篇:技能学习:学习使用Node.js + Vue.js,开发前端全栈网站-13-5.使用字体图标(iconfont)