SimpleDateFormat是线程非安全的
private static final ThreadLocal<DateFormat> DATE_FORMAT_THREAD_LOCAL = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
在《JAVA开发手册》中有提到上述的建议。我们就来详细解释下该建议的来龙去脉。
首先对SimpleDateFormat是非线程安全的进行一下解释。
// 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);
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;
}
从calendar.setTime(date)这句代码可以看出,SimpleDateFormat在format方法中将入参日期对象的时间set到calendar中calendar.setTime(date),calendar是全局变量,在SimpleDateFormat的多个方法中用到,一旦出现多线程调用的情况,calendar的值就会被修改,导致结果不正确甚至发生报错,所以SimpleDateFormat是线程不安全的.
DateTimeFormatter是线程安全的
首先来看一个DateTimeFormatter格式化的实例:
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String format = dateTimeFormatter.format(LocalDateTime.Now());
- DateTimeFormatter#ofPattern
每次都会返回一个新的DateTimeFormatter对象
- DateTimeFormatter#format
Formats a date-time object using this formatter.
This formats the date-time to a String using the rules of the formatter.
temporal the temporal object to format, not null
the formatted string, not null
DateTimeException if an error occurs during formatting
public String format(TemporalAccessor temporal) {
StringBuilder buf = new StringBuilder(32);
formatTo(temporal, buf);
return buf.toString();
}
进入DateTimeFormatter#format函数的实现来看,其缓冲区每次调用都是新建的,进一步查看DateTimeFormatter#formatTo
- DateTimeFormatter#formatTo
Formats a date-time object to an Appendable using this formatter.
This outputs the formatted date-time to the specified destination.
Appendable is a general purpose interface that is implemented by all
key character output classes including StringBuffer, StringBuilder,
PrintStream and Writer.
Although {@code Appendable} methods throw an {@code IOException}, this method does not.
Instead, any {@code IOException} is wrapped in a runtime exception.
temporal the temporal object to format, not null
appendable the appendable to format to, not null
DateTimeException if an error occurs during formatting
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);
}
}
在DateTimeFormatter#formatTo函数中重点注意DateTimePrintContext context = new DateTimePrintContext(temporal, this);这句代码表明传入的日期被封装到一个新的DateTimePrintContext对象中,所以你可以理解DateTimeFormatter#format函数就是一个简单的函数调用,并没有使用到共享数据;所以DateTimeFormatter#format是线程安全的。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。