【Java 陷阱】SimpleDateFormat 时间格式化多线程异常
2015-08-22 14:11
489 查看
SimpleDateFormat 陷阱
SimpleDateFormat是java中常用的时间格式化工具,除了转化时间格式,还可以解析字符串到时间类型,方便好用,但是陷阱就在其中。如果你遇到类似看到时间字符串完全正确,但就是不能正确格式化,或者明明时间类型没错,但就是无法转化为其他格式,亦或是格式转化错误随机出现,那想想,是不是陷入了多线程并发的陷阱。调用:
private static SimpleDateFormat sdf = new SimpleDataFormat("yyyy-MM-dd HH:mm:ss"); ... ... public static Date parseDateFromString(String str){ try{ return sdf.parse(str); }catch(Exception e){ //TODO } } ... ...
多线程情况下数据随机抛出异常:
java.lang.NumberFormatException: multiple points at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1082) at java.lang.Double.parseDouble(Double.java:510) at java.text.DigitList.getDouble(DigitList.java:151) at java.text.DecimalFormat.parse(DecimalFormat.java:1302) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1934) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1311) at java.text.DateFormat.parse(DateFormat.java:335)
这种问题在单机情况下调试难以发现问题,根本原因在于SimpleDateFormat本身不是线程安全的:
SimpleDateFormat.java
*** Date formats are not synchronized.** * It is recommended to create separate format instances for each thread. * If multiple threads access a format concurrently, it must be synchronized * externally. * * @see <a href="http://java.sun.com/docs/books/tutorial/i18n/format/simpleDateFormat.html">Java Tutorial</a> * @see java.util.Calendar * @see java.util.TimeZone * @see DateFormat * @see DateFormatSymbols * @version 1.88, 05/28/08 * @author Mark Davis, Chen-Lieh Huang, Alan Liu */ public class SimpleDateFormat extends DateFormat { ** .. protected Calendar calendar; .. // Called from Format after creating a FieldDelegate private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); ..... } public Date parse(String text, ParsePosition pos) { int start = pos.index; int oldStart = start; int textLength = text.length(); calendar.clear(); // Clears all the time fields ... ... } }
从上面代码片段可以看到,多线程下,对象calendar会被频繁的修改,从而导致不可预知的错误。
解决方案:
SimpleDateFormat 实例化在方法内部,每次重新定义变量不好,导致format对象频繁创建,大并发下影响性能
同步代码块,对sdf共享变量加锁 synchronize(sdf)
不好,并发下加锁会降低系统的并发性能,极限情况下退化为单线程,不推荐
使用ThreadLocal,隔离线程共享变量
推荐使用,类似如下:
private static ThreadLocal<SimpleDateFormat> threadLocal = new ThreadLocal<DateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static Date parse(String dateStr) throws ParseException { return threadLocal.get().parse(dateStr); }public static String format(Date date) { return threadLocal.get().format(date); }
结束
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- Python3写爬虫(四)多线程实现数据爬取
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树