原文:https://www.jianshu.com/p/9824f43807e9
SimpleDateFormat是线程不安全的,一般不要定义为static变量,如果定义为static变量,必须i吉奥索,或者使用DateUtils。
/**
* 定义一个全局的SimpleDateFormat
*/
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
/**
* 使用ThreadFactoryBuilder定义一个线程池
*/
private static ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
private static ExecutorService pool = new ThreadPoolExecutor(5, 200, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(1024), namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
/**
* 定义一个CountDownLatch,保证所有子线程执行完之后主线程再执行
*/
private static CountDownLatch countDownLatch = new CountDownLatch(100);
public static void main(String[] args) throws Exception {
//定义一个线程安全的HashSet
Set<String> dates = Collections.synchronizedSet(new HashSet<String>());
for (int i = 0; i < 100; i++) {
// 获取当前时间
Calendar calendar = Calendar.getInstance();
int finalI = i;
pool.execute(() -> {
//时间增加
calendar.add(Calendar.DATE, finalI);
//通过simpleDateFormat把时间转换成字符串
String dateString = simpleDateFormat.format(calendar.getTime());
// 把字符串放入Set中
dates.add(dateString);
// countDown
countDownLatch.countDown();
});
}
// 阻塞,直到countDown数量为0
countDownLatch.await();
// 输出去重后的时间个数
System.out.println(dates.size());
}
解决方案:
1.使用局部变量。
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
2.同步加锁。
synchronized (simpleDateFormat) {
}
3.使用ThreaLocal。
private static ThreadLocal<SimpleDateFormat> simpleDateFormatThreadLocal = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
Java8 可以用DateTimeFormatter代替SimpleDateFormat。
这一秒不放弃,下一秒有奇迹!