我们可以将 SimpleDateFormat 对象声明为静态对象吗
SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
SimpleDateFormat fullFormat = new SimpleDateFormat("EE MMM dd, HH:mm:ss")
我有几段经常被调用的这样的代码,将它们声明为静态变量是否有意义?
在这种情况下,将动态参数传递给 format()
方法是否是线程安全的?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
不它们不是线程安全的。使用 Joda-time 的版本 相反。
或者将它们包装在同步方法中并使其线程安全
Doc说得很清楚
No they aren't thread-safe.Use Joda-time's version instead.
Or make them wrapped in synchronized method and make it thread-safe
Doc Says it clearly
从 Java 8 开始,新的 Date API 支持这一点。
DateTimeFormatter
是线程安全的,可以完成与SimpleDateFormat
相同的工作。引用自 JavaDoc:更明确地说,定义如下格式是完全可以的:
并在可以由多个线程同时访问的方法中使用它:
As of Java 8, this is supported in the new Date API.
DateTimeFormatter
is thread-safe and can do the same work asSimpleDateFormat
. Cited from the JavaDoc:To be extra clear, it is perfectly fine to define a format such as:
And use it in methods that can be accessed by several threads concurrently:
DateFormat 不是线程安全的。如果多个线程使用相同的 DateFormat 对象而不进行任何同步,您可能会得到意外的结果。因此,您应该同步对 DateFormat 对象的访问、使用 ThreadLocal 变量或使用替代的 Date API(例如 Joda-Time)。
有关如何执行此操作的更多信息,请查看此博客文章:具有多线程的日期格式
DateFormat is not thread-safe. If multiple threads use the same DateFormat object without any synchronization you can get unexpected results. So you should either synchronize access to the DateFormat object, use a ThreadLocal variable or use an alternative Date API such as Joda-Time.
For more information on how to do this, take a look at this blog post: DateFormat with Multiple Threads
如果您已经在使用 Apache Commons,则可以选择:
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/FastDateFormat.html
An alternative if you are already using Apache Commons:
https://commons.apache.org/proper/commons-lang/javadocs/api-2.6/org/apache/commons/lang/time/FastDateFormat.html
SimpleDateFormat
使用起来很简单,但也很复杂。开发人员通常以单个用户身份编写代码并进行测试,并且会成功。但在并行和并发请求的情况下,SimpleDateFormat
是一种复杂的日期格式。在服务或控制器层中暴露为静态,并且当多个线程可以同时访问时,它可能会表现异常。
DateFormat APi 类还建议,“建议为每个线程创建单独的格式实例。如果多个线程同时访问某个格式,则必须在外部对其进行同步。”
用于演示失败的代码多线程环境。
输出 - 这因机器而异,并且会在运行多少次时生成不同的输出。
11 月 11 日星期三 00:00:00 IST 2201
00:00:00
11 月 11 日星期三
IST 2201 1 月 11 日星期五 00:00:00 IST 2019 1 月 11 日星期五 00:00:00 IST 2019
1 月 11 日星期五 00:00:00 IST 2019
00:00:00
1月11日星期五
IST 2019 1月11日星期五 00:00:00 IST 2019 12月31日星期一 00:00:00 IST
2018 1月11日星期五 00:00:00 IST 2019
1月11日星期五 00:00:00 IST 2019
1月11日
星期五 00:00:00 IST 2019
1月11日星期五 00:00:00 IST 2019
1月11日星期五 00:00:00 IST 2019 1月
11日星期五 00:00:00 IST 2019 1月11日星期五 00:00:00 IST 2019
1月11日
星期五 00:00:00 IST 2019
1月11日
星期五 00:00:00 IST 2019 1月11日星期五 00:00:00 IST 2019 1月11日星期日 00:00:00 IST 2201
1月11日星期五 00:00:00 IST 2019
由于
DateFormat
中的 Calendar 实例变量而中断 ->SimpleDateFormat
类。解决方案
使用
ThreadLocal
public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
Java 8、
DateTimeFormatter
APIpublic static Final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
SimpleDateFormat
is simple in use, but yet complicated. Developer generally writes code and test as a single user, and succeeds. but in case of parallel and concurrent requests,SimpleDateFormat
is a complicated dateformat.having exposed as static in service or controller layer, and when multiple threads can access at same time, it can behave abnornally.
DateFormat APi class also recommends, "It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally."
code to demontsrate it's failure in multi threading environment.
Output - This varies from machine to machine and will generate difefrent output how many time you run.
Wed Nov 11 00:00:00 IST 2201
Wed Nov 11 00:00:00 IST 2201
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Mon Dec 31 00:00:00 IST 2018
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Fri Jan 11 00:00:00 IST 2019
Sun Jan 11 00:00:00 IST 2201
Fri Jan 11 00:00:00 IST 2019
This breaks due to Calendar instance variable inside
DateFormat
->SimpleDateFormat
class.Solution
Using
ThreadLocal
public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));
Java 8,
DateTimeFormatter
APIpublic static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
静态应该不是问题。
由于 AFAIK 无法保证线程安全,因此您必须检查源代码。即使您得出的结论是它是线程安全的,这也可能会随着下一个版本而改变。正如另一个答案中所说,它们不是线程安全的。您是否真的分配了如此大量的线程,以至于为每个线程提供自己的格式是一个问题?
static shouldn't be a problem.
Since AFAIK no guarantees are made about thread safety you'd have to check the source code for that. And even if you come to the conclusion that it is thread safe, this might change with the next release.As said in another answer they are not thread safe.Do you really allocate such a huge amount of threads that giving each thread its own Format is a problem?