gpt4 book ai didi

java - 证明 SimpleDateFormat 不是线程安全的

转载 作者:搜寻专家 更新时间:2023-11-01 01:04:04 25 4
gpt4 key购买 nike

我想通过一个简单的 JUnit 测试向同事证明 SimpleDateFormat 不是线程安全的。下面的类没有表达我的观点(在多线程环境中重用 SimpleDateFormat),我不明白为什么。你能发现是什么阻止了我使用 SDF 时抛出运行时异常吗?

public class SimpleDateFormatThreadTest
{
@Test
public void test_SimpleDateFormat_MultiThreaded() throws ParseException{
Date aDate = (new SimpleDateFormat("dd/MM/yyyy").parse("31/12/1999"));
DataFormatter callable = new DataFormatter(aDate);

ExecutorService executor = Executors.newFixedThreadPool(1000);
Collection<DataFormatter> callables = Collections.nCopies(1000, callable);

try{
List<Future<String>> futures = executor.invokeAll(callables);
for (Future f : futures){
try{
assertEquals("31/12/1999", (String) f.get());
}
catch (ExecutionException e){
e.printStackTrace();
}
}
}
catch (InterruptedException e){
e.printStackTrace();
}
}
}

class DataFormatter implements Callable<String>{
static SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy");

Date date;

DataFormatter(Date date){
this.date = date;
}

@Override
public String call() throws RuntimeException{
try{
return sdf.format(date);
}
catch (RuntimeException e){
e.printStackTrace();
return "EXCEPTION";
}
}
}

最佳答案

缺乏线程安全并不一定意味着代码会抛出异常。 Andy Grove 的文章 SimpleDateFormat and Thread Safety 对此进行了解释,不再在线提供。在其中,他展示了 SimpleDateFormat 缺乏线程安全性,方法是展示给定不同的输入,输出并不总是正确的。

When I run this code, I get the following output:

    java.lang.RuntimeException: date conversion failed after 3 iterations.
Expected 14-Feb-2001 but got 01-Dec-2007

Note that "01-Dec-2007" isn't even one of the strings in the test data. It is actually a combination of the dates being processed by the other two threads!

虽然原始文章不再在线提供,但以下代码说明了这个问题。它是根据似乎是基于 Andy Grove 最初文章的文章创建的。

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

public class SimpleDateFormatThreadSafety {
private final SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);

public static void main(String[] args) {
new SimpleDateFormatThreadSafety().dateTest(List.of("01-Jan-1999", "14-Feb-2001", "31-Dec-2007"));
}

public void dateTest(List<String> testData) {
testData.stream()
.map(d -> new Thread(() -> repeatedlyParseAndFormat(d)))
.forEach(Thread::start);
}

private void repeatedlyParseAndFormat(String value) {
for (int i = 0; i < 1000; i++) {
Date d = tryParse(value);
String formatted = dateFormat.format(d);
if (!value.equals(formatted)) {
throw new RuntimeException("date conversion failed after " + i
+ " iterations. Expected " + value + " but got " + formatted);
}
}
}

private Date tryParse(String value) {
try {
return dateFormat.parse(value);
} catch (ParseException e) {
throw new RuntimeException("parse failed");
}
}
}

有时此转换会因返回错误的日期而失败,有时会因 NumberFormatException 而失败:

java.lang.NumberFormatException: For input string: ".E2.31E2"

关于java - 证明 SimpleDateFormat 不是线程安全的,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12533345/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com