`

SimpleDateFormat非线程安全

    博客分类:
  • Java
阅读更多

 

 

问题的引出,这是一个多线程访问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是线程不安全的

    在Java编程语言中,`SimpleDateFormat`类是一个广泛使用的日期时间格式化工具,但它的线程安全性是一个常常被开发者忽视的问题。标题指出的"simpleDateFormat是线程不安全的",意味着在多线程环境下,如果多个线程...

    深入理解Java:SimpleDateFormat安全的时间格式化

    知识点1: SimpleDateFormat的非线程安全性 SimpleDateFormat类不是线程安全的,这意味着在多线程环境下,如果多个线程同时访问同一个SimpleDateFormat实例,可能会导致各种问题,例如转化的时间不正确、报错、线程...

    ThreadLocal:如何优雅的解决SimpleDateFormat多线程安全问题

    目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现...事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...

    高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx

    SimpleDateFormat类的线程安全问题和解决方案 SimpleDateFormat类的线程安全问题 SimpleDateFormat类是Java提供的日期时间转化类,用于将日期和时间类型的数据进行解析和格式化。在Java开发中,SimpleDateFormat类...

    关于SimpleDateFormat的非线程安全问题及其解决方案.docx

    ### 关于SimpleDateFormat的非线程安全问题及其解决方案 #### 一、问题介绍 在Java开发过程中,`SimpleDateFormat`是被广泛使用的日期格式化工具类。然而,在多线程环境下,`SimpleDateFormat`存在非线程安全的...

    详解SimpleDateFormat的线程安全问题与解决方案

    在Java编程中,`SimpleDateFormat`是一个常用的日期时间格式化工具类,但它的设计并不是线程安全的。本文将深入探讨`SimpleDateFormat`的线程安全问题及其解决方案。 ### 1. 线程安全问题的原因 `SimpleDateFormat...

    SimpleDateFormat线程不安全的5种解决方案.md

    SimpleDateFormat线程不安全的5种解决方案.md

    SimpleDateFormat线程不安全的5种解决方案.docx

    JDK 8 引入了新的日期时间 API,其中的 DateTimeFormatter 是线程安全的,可以替代 SimpleDateFormat。以下是使用 DateTimeFormatter 的示例: ```java import java.time.LocalDateTime; import java.time.format....

    Java 55道面试题和答案.docx

    - **SimpleDateFormat非线程安全**:在多线程环境下,使用ThreadLocal封装SimpleDateFormat以保证线程安全,或者使用日期处理库如joda-time。 4. **面向对象和设计原则**: - **SOLID原则**:单一职责、开闭原则...

    Java面试题和答案共55道.docx

    - **SimpleDateFormat非线程安全**:在多线程环境中,每个线程应有自己的SimpleDateFormat实例,通常使用ThreadLocal存储。 4. **OOP与设计模式**: - **SOLID原则**:单一职责、开闭、里氏替换、接口隔离和依赖...

    Java SimpleDateFormat线程安全问题原理详解

    Java SimpleDateFormat线程安全问题原理详解 Java SimpleDateFormat线程安全问题是Java开发中一个常见的问题。SimpleDateFormat是Java中一个常用的日期时间格式化类,但是它却存在线程安全问题。在多线程环境下,...

    Java多线程环境下SimpleDateFormat类安全转换

    在Java多线程环境下,SimpleDateFormat类的使用可能会出现线程安全问题。本文主要介绍了Java多线程环境下SimpleDateFormat类的安全转换,通过示例代码详细介绍了如何解决SimpleDateFormat类多线程环境下转换错误问题...

    Java多线程编程的线程安全性.docx

    Java标准库中有一些类,如ArrayList、HashMap和SimpleDateFormat,并未设计为线程安全,因此在多线程环境下直接使用可能导致数据不一致或其他问题。开发者应当了解每个类的线程安全特性,以便做出正确的选择和适当地...

    Java理论与实践:描绘线程安全性

    这类类在设计时就没有考虑线程安全,例如`SimpleDateFormat`,在1.4 JDK之前的版本中并未明确指出其线程不安全,导致许多开发者在并发场景中误用,引发错误。 在文档中清晰地记录类的线程安全性是至关重要的。如...

    由浅入深解析 SimpleDateFormat

    SimpleDateFormat 详解 SimpleDateFormat 是 Java 语言中...然而,在使用时需要注意线程安全和资源消耗问题。通过合理地使用 SimpleDateFormat,我们可以实现日期和时间的高效格式化和解析,提高程序的性能和可读性。

    Java线程安全的计数器简单实现代码示例

    Java线程安全的计数器简单实现代码示例 Java线程安全的计数器简单实现代码示例是一种在Java中实现线程安全的计数器的方法,该方法使用AtomicInteger和volatile关键字来保证计数器的线程安全性。该计数器可以每天从1...

    java SimpleDateFormat &Calendar

    需要注意的是,由于`SimpleDateFormat`不是线程安全的,所以在多线程环境中,建议为每个线程创建单独的实例。 `Calendar`类则是Java中更底层的日期和时间工具,它提供了一套完整的API来操作日期和时间,包括添加、...

    有关SimpleDateFormat的常用方法说明

    - `SimpleDateFormat`是线程不安全的,如果在多线程环境中使用,需要考虑同步问题。 - 日期和时间的格式化字符串要与实际情况对应,避免出现理解错误。 以上就是关于`SimpleDateFormat`的一些常见用法和注意事项,...

Global site tag (gtag.js) - Google Analytics