Java在并發(fā)環(huán)境中SimpleDateFormat多種解決方案
先來看一個多線程下使用例子,看到運行結果會出現異常:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimpleDateFormateTest {
public static void main(String[] args) {
final DateFormat df = new SimpleDateFormat("yyyyMMdd,HHmmss");
ExecutorService ts = Executors.newFixedThreadPool(100);
for (;;) {
ts.execute(new Runnable() {
@Override
public void run() {
try {
//生成隨機數,格式化日期
String format = df.format(new Date(Math.abs(new Random().nextLong())));
System.out.println(format);
} catch (Exception e) {
e.printStackTrace();
System.exit(1);
}
}
});
}
}
}
運行結果:

在并發(fā)環(huán)境下使用SimpleDateFormat,正常的打開放式如下:
為了能夠在多線程環(huán)境下使用SimpleDateFormat,有這六種方法:
方法一
在需要執(zhí)行格式化的地方都新建SimpleDateFormat實例,使用局部變量來存放SimpleDateFormat實例
public static String formatDate(Date date)throws ParseException{
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return sdf.format(date);
}
這種方法可能會導致短期內創(chuàng)建大量的SimpleDateFormat實例,如解析一個excel表格里的字符串日期。
方法二
為了避免創(chuàng)建大量的SimpleDateFormat實例,往往會考慮把SimpleDateFormat實例設為靜態(tài)成員變量,共享SimpleDateFormat對象。這種情況下就得對SimpleDateFormat添加同步。
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static String formatDate(Date date)throws ParseException{
synchronized(sdf){
return sdf.format(date);
}
}
這種方法的缺點也很明顯,就是在高并發(fā)的環(huán)境下會導致解析被阻塞。
方法三
方法加同步鎖synchronized,在同一時刻,只有一個線程可以執(zhí)行類中的某個方法。
缺點:性能較差,每次都要等待鎖釋放后其他線程才能進入。
方案四 使用第三方包
這個我有嘗試cn.hutool和common-lang3提供的FastDateFormat
最后的結果其實并不滿意,因為這兩個包都沒能幫助我檢查非正常時間,比如2018-07-32這種日期也被認為是正確的時期格式了
方法五(推薦)
要在高并發(fā)環(huán)境下能有比較好的體驗,可以使用ThreadLocal來限制SimpleDateFormat只能在線程內共享,這樣就避免了多線程導致的線程安全問題。
private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
};
public static String format(Date date) {
return threadLocal.get().format(date);
}
方案六 DateTimeFormatter使用
Java8提供了新的日期時間API,其中包括用于日期時間格式化的DateTimeFormatter,它與SimpleDateFormat的有什么區(qū)別呢?
問題解決
兩者最大的區(qū)別是,Java8的DateTimeFormatter也是線程安全的,而SimpleDateFormat并不是線程安全。
解析日期
String dateStr= "2016年10月25日";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date= LocalDate.parse(dateStr, formatter);
日期轉換為字符串
LocalDateTime now = LocalDateTime.now();
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a");
String nowStr = now .format(format);
由DateTimeFormatter的靜態(tài)方法ofPattern()構建日期格式,LocalDateTime和LocalDate等一些表示日期或時間的類使用parse和format方法把日期和字符串做轉換。
使用新的API,整個轉換過程都不需要考慮線程安全的問題。
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
本文給大家分享的是一則使用java編寫的文件管理器的代碼,新人練手的作品,邏輯上還是有點小問題,大家?guī)兔纯窗伞?/div> 2015-04-04
spring boot整合RabbitMQ實例詳解(Fanout模式)
這篇文章主要介紹了spring boot整合RabbitMQ的實例講解(Fanout模式),非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-04-04最新評論

