SimpleDateFormat和ThreadLocal联合使用
SimpleDateFormat线程不安全问题
SimpleDateFormat大家都用过,日期与字符串转换的类,它的方法是线程不安全的。有同学就说了,这个方法不安全也没事啊,不就是做个日期转换,现编写一下代码
package com.huawei.test;import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Locale;
public class ProveNotSafe {
public static void main(String[] args) {
for (int i=0;i<5;i++){
new Thread(new DateFormatTest()).start();
}
}
}
class DateFormatTest implements Runnable{
static SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd", Locale.US);
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+":"+df.parse("2020-09-11"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
运行完后,妥妥的报错了
Thread-4:Fri Sep 11 00:00:00 CST 2020Exception in thread "Thread-1" java.lang.NumberFormatException: For input string: ""
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
at java.lang.Long.parseLong(Long.java:601)
at java.lang.Long.parseLong(Long.java:631)
at java.text.DigitList.getLong(DigitList.java:195)
at java.text.DecimalFormat.parse(DecimalFormat.java:2051)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:2162)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.huawei.test.DateFormatTest.run(ProveNotSafe.java:21)
at java.lang.Thread.run(Thread.java:748)
Exception in thread "Thread-2" Exception in thread "Thread-3" java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.huawei.test.DateFormatTest.run(ProveNotSafe.java:21)
at java.lang.Thread.run(Thread.java:748)
java.lang.NumberFormatException: multiple points
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1890)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
at com.huawei.test.DateFormatTest.run(ProveNotSafe.java:21)
at java.lang.Thread.run(Thread.java:748)
Thread-0:Fri Sep 11 00:00:00 CST 2020
Disconnected from the target VM, address: "127.0.0.1:56922", transport: "socket"
Process finished with exit code 0
没错就是java.lang.NumberFormatException: multiple points
,不怎么常见,跟进异常堆栈,定位到的点是使用parse方法时会把继承自DateFormat类的类变量calendar被clear了正在设置新值,刚好其他线程进来时使用也调用了calendar.clear(),导致当前线程挂壁,则报错。
如果是用format方法倒是不会报错,但是会串其他线程的结果。原因也是一样:只有类变量Calendar多线程
解决方案
方案一:每次都new 一个SimpleDateFormat
每次线程使用新的实例对象,在本例也简单,把static去掉即可。但是消耗的内存过多
方案二:将对象存入ThreadLocal中
class DateFormatTest implements Runnable{ // 将SimpleDateFormat对象放入ThreadLocal,线程只用自己的对象,就不会出现线程共享脏用报错的问题
private ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<SimpleDateFormat>(){
public SimpleDateFormat initialValue(){
SimpleDateFormat sdf= new SimpleDateFormat("yyyy-MM-dd", Locale.US);
return sdf;
}
};
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+":"+threadLocal.get().parse("2020-09-11"));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
方案三:使用JDK8提供的DateTimeFormatter
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss SSS");LocalDateTime now = LocalDateTime.now();
String str = dtf.format(now);
方案四:将SimpleDateFormat对象用sychronized关键字修饰
synchronized (df) { System.out.println(Thread.currentThread().getName() + ":" + df.parse("2020-09-11"));
}
以上是 SimpleDateFormat和ThreadLocal联合使用 的全部内容, 来源链接: utcz.com/z/518066.html