不仅有的线程结果不正确,甚至还有一些线程还出现了异常!
- 为什么SimpleDateFormat类不是线程安全的?
SimpleDateFormat对parse()方法的实现 。关键代码如下:
@Overridepublic Date parse(String text, ParsePosition pos) {...省略中间代码Date parsedDate;try {...parsedDate = calb.establish(calendar).getTime();} catch (IllegalArgumentException e) {...}return parsedDate;}
establish()的实现如下:Calendar establish(Calendar cal) {...省略中间代码cal.clear();for (int stamp = MINIMUM_USER_STAMP; stamp < nextStamp; stamp++) {for (int index = 0; index <= maxFieldIndex; index++) {if (field[index] == stamp) {cal.set(index, field[MAX_FIELD + index]);break;}}}...return cal;}
在多个线程共享SimpleDateFormat时,同时也共享了Calendar引用 , 在如上代码中,calendar首先会进行clear()操作 , 然后进行set操作,在多线程情况下,set操作会覆盖之前的值,而且在后续对日期进行操作时,也可能会因为clear操作被清除导致异常 。四. 解决方案
- 将SimpleDateFormat定义成局部变量,每次使用时都new一个新对象,频繁创建对象消耗大,性能影响一些(JDK文档推荐此做法)
public static Date parse(String strDate) throws ParseException {SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");return sdf.parse(strDate);}
- 维护一个SimpleDateFormat实体,转换方法上使用 Synchronized 保证线程安全:多线程堵塞(并发大系统不推荐)
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");public static String formatDate(Date date)throws ParseException{synchronized(sdf){return sdf.format(date);}}public static Date parse(String strDate) throws ParseException{synchronized(sdf){return sdf.parse(strDate);}}
- 使用ThreadLocal : 线程独享不堵塞,并且减少创建对象的开销(如果对性能要求比较高的情况,推荐这种方式) 。
public static ThreadLocal<DateFormat> threadLocal = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));public static Date parse(String strDate) throws ParseException {return threadLocal.get().parse(strDate);}
- DateTimeFormatter是Java8提供的新的日期时间API中的类,DateTimeFormatter类是线程安全的,可以在高并发场景下直接使用 。
String dateTimeStr= "2016-10-25 12:00:00";DateTimeFormatter formatter02 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStr,formatter02);System.out.println(localDateTime);String format = localDateTime.format(formatter02);System.out.println(format);2016-10-25T12:002016-10-25 12:00:00
最终,我们根据实际情况公共包DateUtil类提供的strConvertDate方法 , 原理是按照方案1来解决该问题 。【SimpleDateFormat线程安全问题排查】
推荐阅读
- 请问苹果手机怎么样(苹果手机的安全性怎么样)
- 信号量 C# 多线程访问之 SemaphoreSlim【C# 进阶】
- Java 多线程写zip文件遇到的错误 write beyond end of stream!
- Java线程未捕获异常处理 UncaughtExceptionHandler
- 一 Pthread 并发编程——深入剖析线程基本元素和状态
- 夯实Java基础,一篇文章全解析线程问题
- 来啦来啦|开源 * 安全 * 赋能 - .NET Conf China
- 四 Java多线程-ThreadPool线程池-2
- 三 Linux--多线程
- 三 Java多线程-ThreadPool线程池