高并发之——SimpleDateFormat类的线程安全问题和解决方案
关于SimpleDateFormat
熟悉Java的同学知道这个类是线程不安全的,但究竟是怎样不安全法,什么原因产生的线程不安全?估计未必全部人都能够答得上来(我也不能,emmmm)
呃,想更好地了解关于 SimpleDateFormat 这个工具类的线程不安全的原因,推荐一位大佬的博客,请参考:高并发之——SimpleDateFormat类的线程安全问题和解决方案
正文
1、SimpleDateFormat 线程不安全的原因
请参考上述博文
2、解决方案
解决方案是有很多的
把 SimpleDateFormat 放到方法里面(不太好)
加 synchronized(不太好)
加 lock (不太好)
使用threadLocal (推荐)
使用 DateTimeFormatter (推荐)
使用joda-time方式(需要引入新依赖,看情况决定使用)
3、列一些demo代码
是为自己记得,参考的博文解释得更清楚些
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Semaphore; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class SimpleDateFormatFix02 { //执行总次数 private static final int EXECUTE_COUNT = 1000; //同时运行的线程数量 private static final int THREAD_COUNT = 20; private static final String DATE_FORMAT = "yyyy-MM-dd"; private static ThreadLocalthreadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT)); // ThreadLocal的另外一种写法 private static ThreadLocal threadLocal2 = new ThreadLocal(); private static SimpleDateFormat getDataFormat(){ SimpleDateFormat simpleDateFormat = threadLocal2.get(); if(null == simpleDateFormat){ simpleDateFormat = new SimpleDateFormat(DATE_FORMAT); threadLocal2.set(simpleDateFormat); } return simpleDateFormat; } // end public static void main(String[] args) throws InterruptedException { final Semaphore semaphore = new Semaphore(THREAD_COUNT); final CountDownLatch countDownLatch = new CountDownLatch(EXECUTE_COUNT); ThreadPoolExecutor executor = new ThreadPoolExecutor(THREAD_COUNT, THREAD_COUNT, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1000)); for (int i = 0; i < EXECUTE_COUNT; i++) { executor.execute(() -> { try { semaphore.acquire(); try { threadLocal.get().parse("2022-01-01"); } catch (ParseException e) { e.printStackTrace(); System.out.println("转换失败"); System.exit(1); } catch (NumberFormatException e) { e.printStackTrace(); System.out.println("转换失败"); System.exit(1); } semaphore.release(); } catch (InterruptedException e) { e.printStackTrace(); System.exit(1); } countDownLatch.countDown(); }); } countDownLatch.await(); executor.shutdown(); System.out.println("finish success!"); } }
嗯,只记录一下ThreadLocal 的写法,其它写法就不写了。
再说多句,
关于 ThreadLocal 的写法也有几种写法,
// 写法之一 private static ThreadLocalthreadLocal3 = new ThreadLocal(){ @Override protected Object initialValue() { return new SimpleDateFormat(DATE_FORMAT); } }; // 写法之二 private static ThreadLocal threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT)); // 写法之三 private static ThreadLocal threadLocal2 = new ThreadLocal(); private static SimpleDateFormat getDataFormat(){ SimpleDateFormat simpleDateFormat = threadLocal2.get(); if(null == simpleDateFormat){ simpleDateFormat = new SimpleDateFormat(DATE_FORMAT); threadLocal2.set(simpleDateFormat); } return simpleDateFormat; } // end
嗯。好了。先记一些吧。