通过源码跟踪发现,SimpleDateFormat调用establish方法后,进入Calendarbuilder类,在establish方法中源码是这样进行描述的。
Calendar establish(Calendar cal) {
boolean weekDate = isSet(WEEK_YEAR)
&& field[WEEK_YEAR] > field[YEAR];
if (weekDate && !cal.isWeekDateSupported()) {
// Use YEAR instead
if (!isSet(YEAR)) {
//当判断后进行set值
set(YEAR, field[MAX_FIELD + WEEK_YEAR]);
}
weekDate = false;
}
//进行清理值
cal.clear();
// Set the fields from the min stamp to the max stamp so that
// the field resolution works in the Calendar.
for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {
for (int index = 0; index <= maxFieldIndex; index++) {
if (field[index] == stamp) {
cal.set(index, field[MAX_FIELD + index]);
break;
}
}
}
if (weekDate) {
int weekOfYear = isSet(WEEK_OF_YEAR) ? field[MAX_FIELD + WEEK_OF_YEAR] : 1;
int dayOfWeek = isSet(DAY_OF_WEEK) ?
field[MAX_FIELD + DAY_OF_WEEK] : cal.getFirstDayOfWeek();
if (!isValidDayOfWeek(dayOfWeek) && cal.isLenient()) {
if (dayOfWeek >= 8) {
dayOfWeek--;
weekOfYear += dayOfWeek / 7;
dayOfWeek = (dayOfWeek % 7) + 1;
} else {
while (dayOfWeek <= 0) {
dayOfWeek += 7;
weekOfYear--;
}
}
dayOfWeek = toCalendarDayOfWeek(dayOfWeek);
}
cal.setWeekDate(field[MAX_FIELD + WEEK_YEAR], weekOfYear, dayOfWeek);
}
return cal;
}
然而看了Calendar内部机制,Calendar并没有线程安全的机制并且本身也不支持线程安全机制。并且set 和clear并没有进行原子性操作。在高并发场景下,同时操作一个SimpleDateFormat时就会发现cal会混乱。然而format()方法也是一样的效果也会导致数据缭乱。
解决方案:
在高并发情况下推荐使用ThreadLocal/DateTimeFormatter/joda-time库方式。