java - 谁能给我一个显示 SimpleDateFormat 线程不安全的例子?

标签 java multithreading thread-safety simpledateformat

我试图编写一个示例来显示 SimpleDateFormat 是线程不安全的。但它不起作用!谁能给我一个显示 SimpleDateFormat 线程不安全的例子?

public static void main(String[] args) throws ParseException, InterruptedException {

    Date aDate = (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2016-12-15 23:59:59"));

    ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 1000);

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    DataFormatter callable = new DataFormatter(sdf, aDate);
    Collection<DataFormatter> callables = Collections.nCopies(1000, callable);
    executor.invokeAll(callables);
    executor.shutdown();
}

private static class DataFormatter implements Callable<String> {

    private SimpleDateFormat sdf;
    private Date aDate;

    public DataFormatter(SimpleDateFormat sdf, Date aDate) {
        this.sdf = sdf;
        this.aDate = aDate;
    }

    @Override
    public String call() throws Exception {
        String format = sdf.format(aDate);
        Assert.assertEquals("2016-12-15 23:59:59", format);
        return format;
    }
}

最佳答案

Can anyone give me an example of showing SimpleDateFormat is thread unsafe?

当然。您的代码的问题在于您试图一遍又一遍地格式化相同日期,因此共享字段永远不会持有不同的值。如果我们查看 SimpleDateFormat 中的代码,我们会发现它扩展了 DateFormat,后者具有共享的 Calendar calendar 字段。这就是类的重入问题。

// shared with everyone else calling the same SimpleDateFormat
protected Calendar calendar;
...
// method from DateFormat that is extended by SimpleDateFormat
private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) {
    calendar.setTime(date);
    ...

顺便说一句,还要注意它使用 StringBuffer 这意味着它使用 synchronized 方法。令人沮丧的是,我们付出了同步性能损失的代价,但我们却无法使用 SimpleDateFormat 重新进入。

这是我对如何演示它的看法。我只是在随机日期运行日期格式两次并检查结果。只有 20 个并发线程时它会立即失败。

public class SimpleDateFormatEnosafe {

    private static final SimpleDateFormat format =
            new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static void main(String[] args) {
        ExecutorService executor = Executors.newCachedThreadPool();
        DataFormatter formatter = new DataFormatter();
        for (int i = 0; i < 20; i++) {
            executor.submit(formatter);
        }
        executor.shutdown();
        // NOTE: this could never finish if all but one thread fails in the pool
    }

    private static class DataFormatter implements Runnable {
        @Override
        public void run() {
            ThreadLocalRandom random = ThreadLocalRandom.current();
            while (true) {
                Date date = new Date(random.nextLong());
                String output1 = format.format(date);
                String output2 = format.format(date);
                if (!output1.equals(output2)) {
                    System.out.println(output1 + " != " + output2);
                    break;
                }
            }
        }
    }
}

关于java - 谁能给我一个显示 SimpleDateFormat 线程不安全的例子?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41158005/

相关文章:

android - 后台工作 - 服务、线程或两者

Python等待并检查文件是否完全由外部程序创建

java - 实现线程时,使用不可变对象(immutable对象)比使用可变对象更好吗?

java - 关于使用 this 实现 equals 来比较 Java 中的对象

java - 如何将 JavaScript 数组发送到表单标签内的 Servlet?

java - 在 Java 中生成多个形状......?

c++ - 在 C++ 中异步读取文件

java - 获取文件路径

c++ - 需要同步全局变量的使用

multithreading - 戈兰 : to goroutine or not to goroutine?