SimpleDateFormat 的線程安全性問題java
public class DateFormat { // 多線程下存在問題,同步鎖可解決 private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); private static class Task implements Runnable { @Override public void run() { try { System.out.println(simpleDateFormat.parse("2019-06-01 01:01:02")); } catch (ParseException e) { e.printStackTrace(); } } } private static void threadTest() { ExecutorService executorService= Executors.newFixedThreadPool(3); Task task = new Task(); Thread t1 = new Thread(task); Thread t2 = new Thread(task); Thread t3 = new Thread(task); Thread t4 = new Thread(task); Thread t5 = new Thread(task); executorService.execute(t1); executorService.execute(t2); executorService.execute(t3); executorService.execute(t4); executorService.execute(t5); executorService.shutdown(); } public static void main(String[] args) { threadTest(); } }
SimpleDateFormat類內部有一個Calendar對象引用,用來儲存這個SimpleDateFormat相關的日期信息,多線程下會共享這個Calendar引用,會致使出現幻讀成員變量的現象安全
解決辦法:多線程
一、將SimpleDateFormat定義成局部變量。ide
缺點:每調用一次方法就會建立一個SimpleDateFormat對象,方法結束又要做爲垃圾回收。性能
二、方法加同步鎖synchronized,在同一時刻,只有一個線程能夠執行類中的某個方法。線程
缺點:性能較差,每次都要等待鎖釋放後其餘線程才能進入。orm
三、使用第三方庫joda-time,由第三方考慮線程不安全的問題。(能夠使用)對象
四、使用ThreadLocal:每一個線程擁有本身的SimpleDateFormat對象。(推薦使用)blog
使用ThreadLocal方式,以下:get
private static final ThreadLocal<SimpleDateFormat> df = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; private static class TaskLocal implements Runnable { @Override public void run() { try { System.out.println(df.get().parse("2019-06-01 01:01:02")); } catch (ParseException e) { e.printStackTrace(); } } }
JDK8的應用,能夠使用Instant代替Date,LocalDateTime代替Calendar,DateTimeFormatter代替Simpledateformatter
public static void main(String[] args) { LocalDateTime arrivalDate = LocalDateTime.now(); DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String landing = arrivalDate.format(format); System.out.println(landing); }