2016-04-22 62 views
3

我最近意识到/了解到SimpleDateFormat有一些严重的问题,因为不应该再使用Java 8了。我的意思是......我有点了解它,但从来没有注意到这一点。到现在为止还挺好。SimpleDateFormat - 不安全,但为什么?

但后来确定......我有很多写在去年7,8年,其确实使用SimpleDateFormat,商店很多SimpleDateFormat对象作为静态字段遗留代码,并用它们来解析/格式的日期。实际上,我从来没有在生产(所有这些年)中对这些实例(静态或不是静态)有任何问题。

所以...我想现在审查和分析这个遗留代码,看看是否真的有在它SimpleDateFormat任何危险用途。

所以我的问题是...

在什么样的情况下究竟是SimpleDateFormat问题使用?
我可以得到某种清单,以便检查我的旧代码,看看我的任何方案是否都在“尽量避免”列表中?

+1

这不是线程安全的,所以如果两个线程同时使用相同的SimpleDateFormat对象,则会出现问题。 – Henry

+0

@亨利是的,我听说过...但确定...是唯一的问题呢? –

+1

如果代码当前正在工作,则不会突然添加新的缺陷。但是,新的日期和时间API很容易正确使用。 –

回答

1

SimpleDateFormat是不是你当线程安全的,从而在每个多线程情况下(例如Web应用程序),你不能在一个常量类中声明一个格式化并使用它周围的所有业务方法不奇怪的错误的风险... expecially开始玩时区等。

3

SimpleDateFormat不是线程安全的,任何你把它放在一个被多线程访问的字段中的场景都将是一个潜在的问题。它不会炸毁你,但它可能会导致不正确的结果。

这样做的分类情况将是检查你使用的结果,以及这些值总是正确的重要性。显然,您碰到格式化程序的线程越多,发生错误的机会就越大,因此多线程应用程序但很少有多个用户的应用程序可能会优先向下。

2

一个问题,例如,是SimpleDateFormat的具有被设置为要格式化的日期/日历内场。

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

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

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

  • 单线程(预期结果):

    [02-JAN-1970四时46分40秒,01-Jan- 1970 01:00:00]

  • 多线程:

    [02-Jan-1970 01:00:00,01-Jan-1970 04:00:00,02-Jan-1970 01:00:40,01-Jan-1970 01:00:40,02-Jan -1970 04:46:00,02-Jan-1970 01:46:00,01-Jan-1970 01:00:00,02-Jan-1970 04:00:00,01-Jan-1970 01:46: 40,02-Jan-1970 04:00:40,01-Jan-1970 01:46:00,01-Jan-1970 01:46:40,02-Jan-1970 04:46:40,01-Jan- 1970年4点零零分40秒,01-JAN-1970年四点46分四十秒,01-JAN-1970年四点46分00秒]


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); 
}