SimpleDateFormat非线程安全

类SimpleDateFormat主要负责日期的转换与格式化,但在多线程的情况下,使用此类容易造成数据转换错误。

用一个例子来演示其线程不安全问题:

输入日期,通过调用parse和format方法,转化为日期字符串,与原日期相比。

package p7;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class MyThread extends Thread{
   private SimpleDateFormat sdf;
   private String dateString;
public MyThread(SimpleDateFormat sdf, String dateString) {
	super();
	this.sdf = sdf;
	this.dateString = dateString;
}
   public void run() {
	   try {
		Date dateRef=sdf.parse(dateString);
		String s=sdf.format(dateRef);
		System.out.println("原时间:"+dateString+" 解析时间:"+s);
	} catch (ParseException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	   
   }
}
package p7;

import java.text.SimpleDateFormat;

public class Test1 {
	public static void main(String[] args) {
		 SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd");
		 String []dateStringArray= {"2000-01-01","2000-01-02","1997-03-04"};
		 MyThread[] myThreads=new MyThread[3];
		 for(int i=0;i<3;i++) {
			 myThreads[i]=new MyThread(simpleDateFormat, dateStringArray[i]);
			 myThreads[i].start();
		 }
	}
}

运行结果如下:


从结果上来看日期通过parse和format转化之后,与原日期不符合,出现数据转换不准确的问题。

下面我们就来分析一下为什么会产生此问题。

通过查看SimpleDateFormat的源代码我们可以发现,SimpleDateFormat内部声明了一个protected的Calendar类型的成员变量,而format()和parse()方法都是对该calendar进行修改。

format方法源代码如下:


因为该方法没有进行同步,当多线程访问的时候都对同一个calendar对象进行操作,导致数据错误。

假设线程1调用format方法执行完calendar.setTime(date)后停止,线程2此时也调用format()方法执行calendar.setTime(date)方法,然后线程1和线程2再继续执行后面的代码,这时候线程1和线程2改变的都是同一个calendar中的值,导致线程访问数据出现差错。

那么在多线程下要如何解决这个问题呢?

方法一:

编写DateTools类,每此调用方法都创建一个SimpleDateFormat对象。

public class DateTools {
   public static Date parse(String formatPattern,String dateString) throws ParseException {
	   return new SimpleDateFormat(formatPattern).parse(dateString);
   }
   public static String format(String formatPattern,Date date) {
	   return new SimpleDateFormat(formatPattern).format(date);
   }
}

方法二:

使用ThreadLocal类,每个线程都拥有自己的SimpleDateFormat对象

class DateTool{
	private static ThreadLocal<SimpleDateFormat>t1=new ThreadLocal<>();
	public static SimpleDateFormat getSimpleDateFormat(String pattern) {
		SimpleDateFormat sdf=null;
		sdf=t1.get();
		if(sdf==null) {
			sdf=new SimpleDateFormat(pattern);
			t1.set(sdf);
		}
		return sdf;
	 }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值