SimpleDateFormat執行緒不安全
阿新 • • 發佈:2021-01-08
技術標籤:java後端
測試程式碼:
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; public class SimpleDateFormatTest { //這裡只建立了一個物件(該物件擁有共享的成員變數protected Calendar calendar;) private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); //ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000)); public void test() { System.out.println("================================1"); int i = 0; while (true) { i++; System.out.println("start................"); poolExecutor.execute(new Runnable() { @Override public void run() { System.out.println("run................"); String dateString = simpleDateFormat.format(new Date()); try { Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); if(!dateString.equals(dateString2)){ return ; } System.out.println("runEnd................"); } catch (ParseException e) { e.printStackTrace(); } } }); System.out.println("end................"); if(i==20){ return; } } } public static void main(String[] args) { SimpleDateFormatTest sdft = new SimpleDateFormatTest(); sdft.test(); } }
輸出:
true
false
true
true
false
出現了false,說明執行緒不安全。
public class TestdateString {
private static SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public static void main(String[] args) throws ParseException {
String dateString = simpleDateFormat.format(new Date());
String dateString2 = simpleDateFormat.format(parseDate);
System.out.println(dateString.equals(dateString2));
}
}
# 擷取部分SimpleDateFormat 程式碼
# 擷取SimpleDateFormat 部分程式碼分析執行緒不安全問題 public class SimpleDateFormat extends DateFormat { ........................... ................................ @Override public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) { pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); } // Called from Format after creating a FieldDelegate private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); //解析,這裡的calendar 來自父類DateFormat 的成員變數calendar ,(只單例建立了一個物件????,被所有執行緒共享??? 所以有執行緒安全問題。) 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; } .................... }
擷取DateFormat 類部分程式碼:
package java.text;
public abstract class DateFormat extends Format {
protected Calendar calendar;
protected NumberFormat numberFormat;
public final static int ERA_FIELD = 0;
public final StringBuffer format(Object obj, StringBuffer toAppendTo,
FieldPosition fieldPosition)
{
if (obj instanceof Date)
return format( (Date)obj, toAppendTo, fieldPosition );
else if (obj instanceof Number)
return format( new Date(((Number)obj).longValue()),
toAppendTo, fieldPosition );
else
throw new IllegalArgumentException("Cannot format given Object as a Date");
}
//抽象方法
public abstract StringBuffer format(Date date, StringBuffer toAppendTo,
FieldPosition fieldPosition);
public final String format(Date date)
{
return format(date, new StringBuffer(),
DontCareFieldPosition.INSTANCE).toString();
}
........................
}
Calendar類
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar> {
................
@SuppressWarnings("ProtectedField")
protected long time;
@SuppressWarnings("ProtectedField")
protected boolean isTimeSet;
@SuppressWarnings("ProtectedField")
protected boolean areFieldsSet;
transient boolean areAllFieldsSet;
public final void setTime(Date date) {
setTimeInMillis(date.getTime());
}
public void setTimeInMillis(long millis) {
// If we don't need to recalculate the calendar field values,
// do nothing.
if (time == millis && isTimeSet && areFieldsSet && areAllFieldsSet
&& (zone instanceof ZoneInfo) && !((ZoneInfo)zone).isDirty()) {
return;
}
time = millis;
isTimeSet = true;
areFieldsSet = false;
computeFields();
areAllFieldsSet = areFieldsSet = true;
}
................
}