1.Date類為可變的,在多線程并發環境中會有線程安全問題。
(1)可以使用鎖來處理并發問題。
(2)使用JDK8 Instant 或 LocalDateTime替代。
2.Calendar的子類為可變的,在多線程并發環境中會有線程安全問題。
(2)使用JDK8 LocalDateTime 替代。
3.DateFormat和SimpleDateFormat不是線程安全的原因
(1)DateFormat中calendar是共享變量,其子類SimpleDateFormat中也是共享變量。
DateFormat源碼:

public abstract class DateFormat extends Format {
/**
* The {@link Calendar} instance used for calculating the date-time fields
* and the instant of time. This field is used for both formatting and
* parsing.
*
* <p>Subclasses should initialize this field to a {@link Calendar}
* appropriate for the {@link Locale} associated with this
* <code>DateFormat</code>.
* @serial
*/
protected Calendar calendar;

(2)SimpleDateFormat format方法源碼:

private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern[i] >>> 8;
int count = compiledPattern[i++] & 0xff;
if (count == 255) {
count = compiledPattern[i++] << 16;
count |= compiledPattern[i++];
}
switch (tag) {
case TAG_QUOTE_ASCII_CHAR:
toAppendTo.append((char)count);
break;
case TAG_QUOTE_CHARS:
toAppendTo.append(compiledPattern, i, count);
i += count;
break;
default:
subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols);
break;
}
}
return toAppendTo;
}

當多個線程同時使用相同的 SimpleDateFormat 對象【如用static修飾的 SimpleDateFormat 】調用format方法時,多個線程會同時調用 calendar.setTime 方法,可能一個線程剛設定好 time 值另外的一個線程馬上把設定的 time 值給修改了導緻傳回的格式化時間可能是錯誤的。
4.SimpleDateFormat線程安全使用。
(1)使用ThreadLocal處理static方法

public static final ThreadLocal<DateFormat> df = new ThreadLocal<DateFormat>() {
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyy-MM-dd");
}
};

System.out.println(df.get().format(new Date()));
2019-12-14
(2)使用JDK8 DateTimeFormatter 替代。
《阿裡巴巴Java開發手冊》
尋找撬動地球的支點(解決問題的方案),杠杆(Java等程式設計語言)已經有了。xkzhangsan