非线程安全的类-SimpleDateFormat

类SimpleDateFormat主要负责日期的转换与格式化,但在多线程的环境中,使用此类容易造成数据转换及处理的不正确,因为SimpleDateFormat并不是线程安全的,我们看一段代码:

package chapter7.testsimpledateformat;

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) {
		this.sdf = sdf;
		this.dateString = dateString;
	}
	
	@Override
	public void run() {
		try {
			super.run();
			Date dateRef = sdf.parse(dateString);
			String newDateStr = sdf.format(dateRef).toString();
			if(!newDateStr.equals(dateString)) {
				System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

 

package chapter7.testsimpledateformat;

import java.text.SimpleDateFormat;

public class Test {
	
	public static void main(String[] args) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"};
		MyThread[] threads = new MyThread[10];
		for(int i=0;i<10;i++) {
			threads[i] = new MyThread(sdf, dateStr[i]);
		}
		for(int i=0;i<10;i++) {
			threads[i].start();
		}
	}

}

 运行结果:

ThreadName=Thread-5报错了 日期字符串:2000-01-06 转换成的日期为:2000-01-02
ThreadName=Thread-6报错了 日期字符串:2000-01-07 转换成的日期为:2000-01-01
ThreadName=Thread-2报错了 日期字符串:2000-01-03 转换成的日期为:2000-01-05
ThreadName=Thread-3报错了 日期字符串:2000-01-04 转换成的日期为:0010-01-10
ThreadName=Thread-4报错了 日期字符串:2000-01-05 转换成的日期为:2000-01-10

解决办法1:

package chapter7.testsimpledateformat;

import java.util.Date;

public class MyThread extends Thread{
	
	private String dateString;
	
	public MyThread(String dateString) {
		this.dateString = dateString;
	}
	
	@Override
	public void run() {
		try {
			super.run();
			Date dateRef = DateTools.parse(dateString);
			String newDateStr = DateTools.format(dateRef);
			if(!newDateStr.equals(dateString)) {
				System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

 

package chapter7.testsimpledateformat;

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

public class DateTools {
	
	private static final String DATE_FORMAT = "yyyy-MM-dd";
	
	public static Date parse(String dateStr) throws ParseException {
		return new SimpleDateFormat(DATE_FORMAT).parse(dateStr);
	}
	
	public static String format(Date date){
		return new SimpleDateFormat(DATE_FORMAT).format(date);
	}

}

 

package chapter7.testsimpledateformat;

public class Test {
	
	public static void main(String[] args) {
		try {
			String[] dateStr = new String[] {"2000-01-01","2000-01-02","2000-01-03","2000-01-04","2000-01-05","2000-01-06","2000-01-07","2000-01-08","2000-01-09","2000-01-10"};
			MyThread[] threads = new MyThread[10];
			for(int i=0;i<10;i++) {
				threads[i] = new MyThread(dateStr[i]);
			}
			for(int i=0;i<10;i++) {
				threads[i].start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

 运行结果:没有打印错误,说明问题解决,解决处理错误的原理其实就是创建多个SimpleDateFormat。

解决方法2:

package chapter7.testsimpledateformat;

import java.util.Date;

public class MyThread extends Thread{
	
	private String dateString;
	
	public MyThread(String dateString) {
		this.dateString = dateString;
	}
	
	@Override
	public void run() {
		try {
			super.run();
			Date dateRef = DateTools.getSimpleDateFormat().parse(dateString);
			String newDateStr = DateTools.getSimpleDateFormat().format(dateRef);
			if(!newDateStr.equals(dateString)) {
				System.out.println("ThreadName="+this.getName()+"报错了 日期字符串:"+dateString+" 转换成的日期为:"+newDateStr);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

 

package chapter7.testsimpledateformat;

import java.text.SimpleDateFormat;

public class DateTools {
	
	private static final String DATE_FORMAT = "yyyy-MM-dd";
	private static ThreadLocal<SimpleDateFormat> tlLocal = new ThreadLocal<SimpleDateFormat>();
	
	public static SimpleDateFormat getSimpleDateFormat() {
		SimpleDateFormat sdf = null;
		sdf = tlLocal.get();
		if(sdf == null) {
			sdf = new SimpleDateFormat(DATE_FORMAT);
			tlLocal.set(sdf);
		}
		return sdf;
	}
	
}

 运行结果:没有输出错误,说明用ThreadLocal可以解决问题,ThreadLocal类能使线程绑定到指定的对象。

 

posted @ 2019-06-28 15:17  断了线的风筝~  阅读(155)  评论(0编辑  收藏  举报