首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SimpleDateFormat -不安全,但是为什么呢?

SimpleDateFormat -不安全,但是为什么呢?
EN

Stack Overflow用户
提问于 2016-04-22 21:21:48
回答 3查看 238关注 0票数 3

我最近意识到/了解到SimpleDateFormat有一些严重的问题,因为Java8不应该再使用了。我是说..。我知道这一点,但我从来没有注意到这一点。到目前一切尚好。

但是然后好吧..。我在过去的7-8年中编写了很多遗留代码,这些代码使用SimpleDateFormat,将许多SimpleDateFormat对象存储为静态字段,并使用它们来解析/格式化日期。实际上,在生产环境中(这些年),我从未遇到过这些SimpleDateFormat实例(静态或非静态)的任何问题。

所以..。现在,我想回顾和分析这段遗留代码,看看其中是否真的存在SimpleDateFormat的危险用法。

因此我的问题是...

在什么情况下使用SimpleDateFormat是有问题的?

我可以得到某种检查表,这样我就可以检查我的旧代码,看看我的场景是否在“尽量避免”列表中吗?

EN

回答 3

Stack Overflow用户

发布于 2016-04-22 21:26:42

SimpleDateFormat不是线程安全的,任何你把它放在一个可以被多个线程访问的字段中的场景都会是一个潜在的问题。它不会在你身上爆炸,但它可能会导致生成错误的结果。

对这种情况进行分类的问题是检查您使用结果的目的以及这些值始终正确的重要性。显然,格式化程序中的线程越多,出错的可能性就越大,因此多线程但很少有多个用户的应用程序的优先级可能会降低。

票数 3
EN

Stack Overflow用户

发布于 2016-04-22 21:36:01

例如,一个问题是SimpleDateFormat有一个内部字段,该字段设置为您想要格式化的日期/日历。

因此,如果有两个线程同时使用相同的SDF和两个不同的日期,则要格式化的日期可能会在格式化过程中更改,从而导致字符串是两个日期之间的混合。

这就是下面的例子所模拟的。如果使用ExecutorService es = Executors.newFixedThreadPool(1); (单线程)运行它,则如预期的那样,结果集只有两个日期。如果改用ExecutorService es = Executors.newFixedThreadPool(10); (多线程),结果集可能会有更多的日期,这是两个日期的混合。

例如,在我的机器上,输出是:

  • 单线程(预期结果):

02-Jan-1970 04:46:40,01-Jan-1970 01:00:00

  • 多线程:

197001:00:00,01-Jan-1970 04:00:00,02-Jan-1970 01:00:40,01-Jan-1970 04:46:00,02-Jan-1970 01:46:00,01-Jan-1970 01:46:00,02-Jan-1970 04:00:00,02-Jan-1970 01:46:40,01-Jan-1970 01:46:00,01-Jan-1970 01:46:40,02-Jan-1970 04:46:40,01-Jan-1970 04:00:40,01-Jan-1970 04:46:40,01-Jan-1970 04:46:00

代码语言:javascript
复制
private static final DateFormat FMT = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
private static final CountDownLatch LATCH = new CountDownLatch(1);

public static void main(String[] args) throws Exception {
  ExecutorService es = Executors.newFixedThreadPool(1);
  Date d1 = new Date(0);
  Date d2 = new Date(100_000_000);
  List<Future<String>> futures = new ArrayList<> ();
  for (int i = 0; i < 10_000; i++) {
    Date d = i % 2 == 0 ? d1 : d2;
    Future<String> f = es.submit(() -> run(d));
    futures.add(f);
  }
  LATCH.countDown();
  es.shutdown();
  es.awaitTermination(5, TimeUnit.SECONDS);
  Set<String> results = new HashSet<> ();
  for (Future<String> f : futures) {
    results.add(f.get());
  }

  System.out.println(results);
}

private static String run(Date d) throws InterruptedException {
  LATCH.await();
  return FMT.format(d);
}
票数 2
EN

Stack Overflow用户

发布于 2016-04-22 21:26:15

特别是当你开始使用时区之类的东西的时候。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36795033

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档