我们可以将 SimpleDateFormat 对象声明为静态对象吗

发布于 2024-11-10 07:11:24 字数 258 浏览 4 评论 0 原文

SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
SimpleDateFormat fullFormat = new SimpleDateFormat("EE MMM dd, HH:mm:ss")

我有几段经常被调用的这样的代码,将它们声明为静态变量是否有意义?

在这种情况下,将动态参数传递给 format() 方法是否是线程安全的?

SimpleDateFormat monthFormat = new SimpleDateFormat("MMMM");
SimpleDateFormat fullFormat = new SimpleDateFormat("EE MMM dd, HH:mm:ss")

I have several such piece of code which gets invoked often, would it make sense to declare them as static variables?

Is it thread safe to pass dynamic arguments to the format() method in such cases?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

§对你不离不弃 2024-11-17 07:11:24

它们不是线程安全的。使用 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

Date formats are not synchronized. It
is recommended to create separate
format instances for each thread. If
multiple threads access a format
concurrently, it must be synchronized
externally.

一人独醉 2024-11-17 07:11:24

从 Java 8 开始,新的 Date API 支持这一点。 DateTimeFormatter 是线程安全的,可以完成与 SimpleDateFormat 相同的工作。引用自 JavaDoc:

从模式创建的格式化程序可以根据需要多次使用,它是不可变的并且是线程安全的。

更明确地说,定义如下格式是完全可以的:

private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");

并在可以由多个线程同时访问的方法中使用它:

String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);

As of Java 8, this is supported in the new Date API. DateTimeFormatter is thread-safe and can do the same work as SimpleDateFormat. Cited from the JavaDoc:

A formatter created from a pattern can be used as many times as necessary, it is immutable and is thread-safe.

To be extra clear, it is perfectly fine to define a format such as:

private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy MM dd");

And use it in methods that can be accessed by several threads concurrently:

String text = date.toString(formatter);
LocalDate date = LocalDate.parse(text, formatter);
香橙ぽ 2024-11-17 07:11:24

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

呆橘 2024-11-17 07:11:24

SimpleDateFormat 使用起来很简单,但也很复杂。开发人员通常以单个用户身份编写代码并进行测试,并且会成功。但在并行和并发请求的情况下,SimpleDateFormat 是一种复杂的日期格式。

在服务或控制器层中暴露为静态,并且当多个线程可以同时访问时,它可能会表现异常。

DateFormat APi 类还建议,“建议为每个线程创建单独的格式实例。如果多个线程同时访问某个格式,则必须在外部对其进行同步。

用于演示失败的代码多线程环境。

public final class DateUtils {

    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    private DateUtils() {
    }

    public static Date parse(String target) throws ParseException {
        return DATE_FORMAT.parse(target);
    }

    public static String format(Date target) {
        return DATE_FORMAT.format(target);
    }

    private static void testSimpleDateFormatWithThreads() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        final String source = "2019-01-11";

        IntStream.rangeClosed(0, 20)
                .forEach((i) -> executorService.submit(() -> {
                    try {
                        System.out.println(DateUtils.parse(source));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }));

        executorService.shutdown();
    }

    public static void main(String[] args) {
        testSimpleDateFormatWithThreads();
    }
}

输出 - 这因机器而异,并且会在运行多少次时生成不同的输出。

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 类。

解决方案

  1. 使用ThreadLocal

    public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

  2. Java 8、DateTimeFormatter API

    public 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.

public final class DateUtils {

    public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    private DateUtils() {
    }

    public static Date parse(String target) throws ParseException {
        return DATE_FORMAT.parse(target);
    }

    public static String format(Date target) {
        return DATE_FORMAT.format(target);
    }

    private static void testSimpleDateFormatWithThreads() {
        ExecutorService executorService = Executors.newFixedThreadPool(5);

        final String source = "2019-01-11";

        IntStream.rangeClosed(0, 20)
                .forEach((i) -> executorService.submit(() -> {
                    try {
                        System.out.println(DateUtils.parse(source));
                    } catch (ParseException e) {
                        e.printStackTrace();
                    }
                }));

        executorService.shutdown();
    }

    public static void main(String[] args) {
        testSimpleDateFormatWithThreads();
    }
}

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

  1. Using ThreadLocal

    public static final ThreadLocal SIMPLE_DATE_FORMAT = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd"));

  2. Java 8, DateTimeFormatter API

    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");

中性美 2024-11-17 07:11:24

静态应该不是问题。

由于 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?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文