我想让以下代码线程安全。实现它的最佳方法是什么?
private static final DateFormat DATE_FORMAT = DateFormat.getDateTimeInstance();
public static final String eventTypeToDateTimeString(long timestamp)
{
return DATE_FORMAT.format(new Date(timestamp));
}
答案 0 :(得分:10)
The troublesome old date-time classes bundled with the earliest versions of Java have been supplanted by the java.time classes. The java.time classes are thread-safe and use immutable objects.
Replace your formatter and date types with java.time types to automatically get thread-safety.
Define your DateTimeFormatter
globally if so desired. That class can automatically localize the string being generated, or you can specify a certain format.
FormatStyle
to determine length of abbreviation.Locale
to determine (a) the human language for translation of name of day, name of month, and such, and (b) the cultural norms deciding issues of abbreviation, capitalization, punctuation, and such.ZoneId
for a time zone in which to adjust the moment.The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds. The ZonedDateTime
class adjusts an Instant
into a particular time zone.
Your code, translated to java.time classes. In real work I would break this out into multiple lines, and would trap for exceptions.
private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.FULL ).withLocale( Locale.CANADA_FRENCH ) ;
private static final ZoneId ZONE_ID = ZoneId.of( "America/Montreal" );
public static final String eventTypeToDateTimeString(long timestamp)
{
return Instant.ofEpochMilli( timestamp ).atZone( ZONE_ID ).format( DATE_TIME_FORMATTER );
}
I do not advise passing around a long
as a way of representing date-time values. Makes debugging and logging difficulty as a human cannot discern the meaning of the date-time value. Instead, pass around the java.time types such as Instant
. Using the java.time types provides type-safety and makes your code more self-documenting.
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.*
classes.
Where to obtain the java.time classes?
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.
答案 1 :(得分:4)
有几种选择,有不同的权衡。
您可以同步对单个DateFormat的访问。这样可以最大限度地减少创建的格式化程序对象的数量,但不同的线程在访问格式化程序之前必须争用锁定。这可能是表现最差的替代方案;很多线程最终都会花费时间等待,而且你所拥有的线程越多,这就越糟糕。
您可以为每次使用创建一个新的DateFormat对象。这将消除线程之间的争用,但如果有很多日期格式化,你可以用这种方法对垃圾收集器施加压力,这将损害性能。但是在很多情况下这可以很好地工作,并且非常简单。
第三种方法,使DateFormat成为一个threadlocal变量,效率更高。线程之间没有争用,并且格式化程序可以被线程重复使用,因此它不会产生太多的垃圾。缺点是它是最简单的方法,如果你不清除它们,你放在threadLocal中的任何对象可能会比你想要的更长时间。
答案 2 :(得分:3)
只需在每次调用时创建一个新副本,直到它实际证明是性能问题。手动管理线程本地的开销可能会淹没您从缓存中获得的任何优势。
答案 3 :(得分:2)
你可以
每次需要时创建一个新的DateFormat
实例。
按照@Giovanni Botta的指示使用synchronized
块。
使用ThreadLocal
:
private static final ThreadLocal<DateFormat> THREADLOCAL_FORMAT =
new ThreadLocal<DateFormat>() {
@Override protected DateFormat initialValue() {
return DateFormat.getDateTimeInstance();
}
};
public static final String eventTypeToDateTimeString(long timestamp) {
return THREADLOCAL_FORMAT.get().format(new Date(timestamp));
}
实际上,如果你有一个线程池(意味着线程被重用),使用ThreadLocal
可能会给你最好的性能,这是大多数网络容器所做的。
http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html
答案 4 :(得分:2)
更好,使用:org.apache.commons.lang.time.FastDateFormat(是SimpleDateFormat的快速且线程安全的版本)
答案 5 :(得分:0)
最简单的解决方案是:
synchronized public static final String eventTypeToDateTimeString(long timestamp) {
return DATE_FORMAT.format(new Date(timestamp));
}
无需使用ThreadLocal
,因为这一切都在静态环境中。