1.SimpleDateFormat线程不安全
输出时间不安全
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++];
}
public abstract class DateFormat extends Format {
protected Calendar calendar;
public class SimpleDateFormat extends DateFormat
可以看出calendar当多个线程访问的时候会存在不安全的情况,因为calendar数值可能被改变。
输出格式线程不安全
再看SimpleDateFormat的构造器
public SimpleDateFormat(String pattern, Locale locale)
{
if (pattern == null || locale == null) {
throw new NullPointerException();
}
initializeCalendar(locale);
this.pattern = pattern;
this.formatData = DateFormatSymbols.getInstanceRef(locale);
this.locale = locale;
initialize(locale);
}
追踪pattern发现pattern数值可被修改
public void applyLocalizedPattern(String pattern) {
String p = translatePattern(pattern,
formatData.getLocalPatternChars(),
DateFormatSymbols.patternChars);
compiledPattern = compile(p);
this.pattern = p;
}
测试样例:
public static void main(String[] args){
SimpleDateFormat df=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date=new Date();
System.out.println(df.format(date));
df.applyLocalizedPattern("G");
System.out.println(df.format(date));
}
测试结果:
2022-07-05 09:35:30
公元
确保时间安全的样例代码:
public static final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
public static void main(String[] args) {
synchronized (df){
Date date = new Date();
System.out.println(df.format(date));
}
}
但是final修饰仍然可以改变pattern 。
2.DateTimeFormatter线程安全
所有变量包括他自己都是使用final修饰的。
public final class DateTimeFormatter {
/**
* The printer and/or parser to use, not null.
*/
private final CompositePrinterParser printerParser;
/**
* The locale to use for formatting, not null.
*/
private final Locale locale;
/**
* The symbols to use for formatting, not null.
*/
private final DecimalStyle decimalStyle;
/**
* The resolver style to use, not null.
*/
private final ResolverStyle resolverStyle;
/**
* The fields to use in resolving, null for all fields.
*/
private final Set<TemporalField> resolverFields;
/**
* The chronology to use for formatting, null for no override.
*/
private final Chronology chrono;
/**
* The zone to use for formatting, null for no override.
*/
private final ZoneId zone;
使用样例:
DateTimeFormatter dateTimeFormatter=DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
String str1 = dateTimeFormatter.format(LocalDateTime.now());
System.out.println(str1);
String dateStr= "2018年12月18日";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
LocalDate date2= LocalDate.parse(dateStr, formatter);
dateTimeFormatter.parse(str1);
根据查看源码,不涉及对自身属性或者方法的修改,可以认为只是方法调用,
public void formatTo(TemporalAccessor temporal, Appendable appendable) {
Objects.requireNonNull(temporal, "temporal");
Objects.requireNonNull(appendable, "appendable");
try {
DateTimePrintContext context = new DateTimePrintContext(temporal, this);
if (appendable instanceof StringBuilder) {
printerParser.format(context, (StringBuilder) appendable);
} else {
// buffer output to avoid writing to appendable in case of error
StringBuilder buf = new StringBuilder(32);
printerParser.format(context, buf);
appendable.append(buf);
}
} catch (IOException ex) {
throw new DateTimeException(ex.getMessage(), ex);
}
}
printerParser成员是final修饰,printerParser.format方法代码如下,其中成员属性optional也是final修饰,
public boolean format(DateTimePrintContext context, StringBuilder buf) {
int length = buf.length();
if (optional) {
context.startOptional();
}
try {
for (DateTimePrinterParser pp : printerParsers) {
if (pp.format(context, buf) == false) {
buf.setLength(length); // reset buffer
return true;
}
}
} finally {
if (optional) {
context.endOptional();
}
}
return true;
}
通过查询发现parse也是如此。