Java 8
概述
写了若干年Java了, 却不知道 SimpleDateFormat 不是线程安全的,难受啊!
以至于写出了下面的代码:发布于博客园
public final class TimeUtils {
// 线程不安全的用法
public static final SimpleDateFormat SDF_19 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}
在工具类里面定义了一个静态常量,然后,所有线程都用它。
这种状况持续了很久。
直到最近做一个测试才发现,这个做法在多线程环境先是 完完全全错误的!
模拟多线程使用上面的 SimpleDateFormat 对象。发布于博客园
使用parse函数
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.stream.IntStream;
public class SimpleDateFormatMain {
public static Consumer<Object> cs = System.out::println;
public static final SimpleDateFormat SDF_19 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
private static ExecutorService es = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws InterruptedException {
useParse();
}
private static void useParse() throws InterruptedException {
IntStream.range(0, 5).forEach(i->{
es.execute(()->{
try {
// 1、parse 发生异常
cs.accept(i);
Date pdate = SDF_19.parse("2022-01-02 14:14:14");
cs.accept(i + "、Parsed date=" + pdate);
} catch (ParseException e) {
e.printStackTrace();
}
});
});
TimeUnit.SECONDS.sleep(5);
cs.accept("useParse END");
es.shutdown();
}
}
执行结果:发生异常
Exception in thread “pool-1-thread-4” Exception in thread “pool-1-thread-1” Exception in thread “pool-1-thread-2” Exception in thread “pool-1-thread-5” Exception in thread “pool-1-thread-3” java.lang.NumberFormatException: For input string: “1101.E11012E”
使用format函数
private static void useFormat() throws InterruptedException {
IntStream.range(0, 5).forEach(i->{
es.execute(()->{
// 2、format 结果错误-相同值
long rand = ThreadLocalRandom.current().nextLong(1_0000_0000);
long ms = System.currentTimeMillis() + rand;
Date msDate = new Date(ms);
cs.accept(i + "、rand=" + rand + ", ms=" + ms + ", msDate=" + msDate);
String formatString = SDF_19.format(msDate);
cs.accept(i + "、formatString=" + formatString);
});
});
TimeUnit.SECONDS.sleep(5);
cs.accept("useParse END");
es.shutdown();
}
执行结果:发布于博客园
注意,将上吗的 es.execute 改为 es.submit 是不会发生异常的,这里需要使用的 es.execute。
解决方案-1
每次新建一个 SimpleDateFormat 对象,然后再执行其 parse、format 方法。发布于博客园
// Date pdate = SDF_19.parse("2022-01-02 14:14:14");
// 解决方案-1
SimpleDateFormat sdf19 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date pdate = sdf19.parse("2022-01-02 14:14:14");
// String formatString = SDF_19.format(msDate);
// 解决方案-1
SimpleDateFormat sdf19 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formatString = sdf19.format(msDate);
执行结果:发布于博客园
疑问:
为何如此?发布于博客园
有解决方案1,是否还有其它解决方案?
还有哪些常用的Java类不是线程安全的呢?
发布于博客园
参考
1、JAVA系列:SimpleDateFormat使用注意事项之线程不安全性
https://blog.51cto.com/NIO4444/3838670
2、SimpleDateFormat线程不安全原因及解决方案
https://www.cnblogs.com/yangyongjie/p/11017409.html
3、
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289342.html