问题的引出,这是一个多线程访问SimpleDateFormat的测试类
public class DateUtilTest { public static class TestSimpleDateFormatThreadSafe extends Thread { @Override public void run() { while ( true ) { try { this.join(2000); } catch ( InterruptedException e1 ) { e1.printStackTrace(); } try { System.out.println(this.getName() + ":" + DateUtil.parse("2013-05-24 06:02:20")); } catch ( ParseException e ) { e.printStackTrace(); } } } } public static void main( String[] args ) { for ( int i = 0 ; i < 10 ; i++ ) { new TestSimpleDateFormatThreadSafe().start(); } } }
运行时会出现如下Exception
java.lang.NumberFormatException: For input string: "" java.lang.NumberFormatException: multiple points
原因是DateFormate类中有个Calendar变量是全局,这个变量在子类SimpleDateFormat类在两个方法中被调用
private StringBuffer format(Date date, StringBuffer toAppendTo,FieldDelegate delegate) private void subFormat(int patternCharIndex, int count,FieldDelegate delegate, StringBuffer buffer,boolean useDateFormatSymbols)
这时多线程访问就是非线程安全的
public abstract class DateFormat extends Format { protected Calendar calendar; }
解决办法:
方法一:每次创建都new一个新的
public class DateUtil { public static String formatDate(Date date)throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(date); } public static Date parse(String strDate) throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.parse(strDate); } }
方法二:使用同步
public class DateSyncUtil { 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 class ConcurrentDateUtil { private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() { @Override protected DateFormat 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); } }
另一中ThreadLocal方法
public class ThreadLocalDateUtil { private static final String date_format = "yyyy-MM-dd HH:mm:ss"; private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(); public static DateFormat getDateFormat() { DateFormat df = threadLocal.get(); if(df==null){ df = new SimpleDateFormat(date_format); threadLocal.set(df); } return df; } public static String formatDate(Date date) throws ParseException { return getDateFormat().format(date); } public static Date parse(String strDate) throws ParseException { return getDateFormat().parse(strDate); } }
commons-lang.jar中提供了FastDateFormt,是一个thread-safe,性能上也能还是可以的
FastDateFormat fdf = FastDateFormat.getInstance("yyyy-MM-dd", TimeZone.getDefault(), Locale.getDefault()); DateFormatUtils.ISO_DATE_FORMAT.format(new Date())
DateFormatUtils是一个FastDateFormat工具类,提供了一些format常量
ISO_DATE_FORMAT yyyy-MM-dd"2004-01-02" ISO_DATE_TIME_ZONE_FORMAT yyyy-MM-ddZZ"2004-01-02-07:00" ISO_DATETIME_FORMAT yyyy-MM-dd'T'HH:mm:ss"2004-01-02T23:22:12" ISO_DATETIME_TIME_ZONE_FORMAT yyyy-MM-dd'T'HH:mm:ssZZ"2004-01-02T21:13:45-07:00" ISO_TIME_FORMAT 'T'HH:mm:ss"T04:23:22" ISO_TIME_NO_T_FORMAT HH:mm:ss"05:12:34" ISO_TIME_NO_T_TIME_ZONE_FORMAT HH:mm:ssZZ"12:32:22-07:00" ISO_TIME_TIME_ZONE_FORMAT 'T'HH:mm:ssZZ"T18:23:22-07:00" SMTP_DATETIME_FORMAT EEE, dd MMM yyyy HH:mm:ss Z"Wed, 01 Feb 2004 20:03:01 CST"
相关推荐
目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现...事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...
NULL 博文链接:https://flynndang.iteye.com/blog/711878
关于SimpleDateFormat的非线程安全问题及其解决方案.docx
主要介绍了SimpleDateFormat的线程安全问题与解决方案,非常不错,具有参考借鉴价值,需要的朋友可以参考下
SimpleDateFormat线程不安全的5种解决方案.md
SimpleDateFormat线程不安全的5种解决方案.docx
高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx
Java标准库中的一些类如ArrayList、HashMap和SimpleDateFormat,都是非线程安全的,在多线程环境下直接使用它们可能导致一些非预期的结果,甚至是一些灾难性的结果。一般来说,Java标准库中的类在其API文档中会说明...
主要介绍了Java SimpleDateFormat线程安全问题原理详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
主要介绍了Java多线程环境下SimpleDateFormat类安全转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
SimpleDateFormat 是 Java 中一个非常常用的类,该类用来对日期字符串进行解析和格式化输出,但如果使用不小心会导致非常微妙和难以调试的问题,因为 DateFormat 和 SimpleDateFormat 类不都是线程安全的,在多线程...
1. SimpleDateFormat 不是线程安全的 2.cache模型里面字段数据范围 3.字符串不变性 4.HashCode被设计用来提高性能
这份软件安全监测报告主要是监测java开发程序中出现的安全问题,找了一个项目程序监测后出现的原版报告显示,在使用DES加解密的情况下,会被检测...还有关于SimpleDateFormat线程不安全的问题,都有详细解释及处理方法
findbug的错误日志文档... 上面的英文解释其实应该说得比较清楚,在Java文档中,已经明确说明了DateFormats 是非线程安全的,而在SimpleDateFormat的Jdk 的Source文件中,我们也找到这么一段注释,说明它不是线程安全的
4.安全 5.动态 1.4 java 与C/C++之关系 如果你学习过C++语言,你会感觉Java很眼熟,因为Java中许多基本语句的语法和C++一样,像常用的循环语句、控制语句等和C++几乎一样,但不要误解为Java是C++的增强版,Java...
如何线程安全的使用 SimpleDateFormat jdk.volatilex VolatileArrays: volatile 例子 jdk.collection.union JDK: javaAPI 方式 取得集合的交并集 (或者apache的API) largedata 大数据相关算法 目录见 larg
Collections是针对集合类的帮助类,它提供了一系列针对集合的搜索,排序,线程安全化等操作。 final、finally、finalize的区别? 答:final用于声明属性方法和类,分别表示:属性不可变,方法不可覆盖,类不可继承...