DOS之for迴圈用法說明
阿新 • • 發佈:2022-03-17
在java8之前,我們對時間的格式化處理,一般都是用的SimpleDateFormat
類實現的。例如:
@Service
public class SimpleDateFormatService {
public Date time(String time) throws ParseException {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
return dateFormat.parse(time);
}
}
如果你真的這樣寫,是沒問題的。
就怕哪天抽風,你覺得dateFormat是一段固定的程式碼,應該要把它抽取成常量。
於是把程式碼改成下面的這樣:
@Service
public class SimpleDateFormatService {
private static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public Date time(String time) throws ParseException {
return dateFormat.parse(time);
}
}
dateFormat物件被定義成了靜態常量,這樣就能被所有物件共用。
如果只有一個執行緒呼叫time方法,也不會出現問題。
但Serivce類的方法,往往是被Controller類呼叫的,而Controller類的介面方法,則會被tomcat
的執行緒池
呼叫。換句話說,可能會出現多個執行緒呼叫同一個Controller類的同一個方法,也就是會出現多個執行緒會同時呼叫time方法的情況。
而time方法會呼叫SimpleDateFormat
類的parse
方法:
@Override
public Date parse(String text, ParsePosition pos) {
...
Date parsedDate;
try {
parsedDate = calb.establish(calendar).getTime();
...
} catch (IllegalArgumentException e) {
pos.errorIndex = start;
pos.index = oldStart;
return null;
}
return parsedDate;
}
該方法會呼叫establish
方法:
Calendar establish(Calendar cal) {
...
//1.清空資料
cal.clear();
//2.設定時間
cal.set(...);
//3.返回
return cal;
}
其中的步驟1、2、3是非原子操作。
但如果cal物件是區域性變數還好,壞就壞在parse方法呼叫establish方法時,傳入的calendar是SimpleDateFormat
類的父類DateFormat
的成員變數:
public abstract class DateFormat extends Forma {
....
protected Calendar calendar;
...
}
這樣就可能會出現多個執行緒,同時修改同一個物件即:dateFormat,他的同一個成員變數即:Calendar值的情況。
這樣可能會出現,某個執行緒設定好了時間,又被其他的執行緒修改了,從而出現時間錯誤的情況。
那麼,如何解決這個問題呢?
- SimpleDateFormat類的物件不要定義成靜態的,可以改成方法的區域性變數。
- 使用ThreadLocal儲存SimpleDateFormat類的資料。
- 使用java8的DateTimeFormatter類。
來自:
https://mp.weixin.qq.com/s/GCJaMeKiqyHd8okIP5Y_sQ