原文: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。
這一秒不放棄,下一秒有奇蹟!