③. 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(); } } }
④. 阿里规范怎么说的?
③. ThreadLocal源码分析
①. Thread|ThreadLocal|ThreadLocalMap关系
- ①. Thread和ThreadLocal
②. ThreadLocal和ThreadLocalMap
③. 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对象,每个线程都有自己的变量副本
//核心代码说明 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); }