【多线程】高并发之——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 ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT));
// ThreadLocal的另外一种写法
private static ThreadLocal<SimpleDateFormat> 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 ThreadLocal<SimpleDateFormat> threadLocal3 = new ThreadLocal(){
@Override
protected Object initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
// 写法之二
private static ThreadLocal<SimpleDateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat(DATE_FORMAT));
// 写法之三
private static ThreadLocal<SimpleDateFormat> 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

嗯。好了。先记一些吧。

posted @   aaacarrot  阅读(169)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
点击右上角即可分享
微信分享提示