不仅有的线程结果不正确,甚至还有一些线程还出现了异常!
- 为什么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来解决该问题 。经验总结扩展阅读
- 游泳别穿白色泳衣 穿什么颜色的泳衣更安全
- 你认为代餐食品安全吗 代餐减肥的原理是什么
- 201不锈钢餐具安全吗
- 请问苹果手机怎么样(苹果手机的安全性怎么样)
- 地插座安全吗?
- 信号量 C# 多线程访问之 SemaphoreSlim【C# 进阶】
- 水龙头加热器安全吗?
- 拼多多三人团安全吗 拼多多三人团会泄露信息吗
- 安全插座哪种好?
- 驾驶员安全告诫内容 行车安全警示语大全最新