首先看下JDK原始文档SimpleDateFormat的描述:
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.
因此SimpleDateFormat带来的严重的性能问题,创建一个 SimpleDateFormat实例的开销比较昂贵,解析字符串时间时频繁创建生命周期短暂的实例导致性能低下。即使将 SimpleDateFormat定义为静态类变量,貌似能解决这个问题,但是SimpleDateFormat是非线程安全的,同样存在问题,如果用 ‘synchronized’线程同步同样面临问题,同步导致性能下降(线程之间序列化的获取SimpleDateFormat实例)。
为什么创建一个simpleDateFormat会花费很大的代价了?
note that performance is bad because SimpleDateFormat has a calendar instance as a member and it is allocation of
the calendar object that is expensive. This is also why it isn’t thread safe –
if
2
threads change the calendar da
te or timezone or something at once the formats returned will be inconsistent.
上面的解释在于simpleDateFormat有一个calender的实例变量,分配这个变量的代价是昂贵的。这也是为什么它不是线程安全的原因了,如果2个线程同时修改了这个calendar的时间信息,那么format的输出自然是不正确的。
private
StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
calendar.setTime(date);
为了解决线程安全问题可以使用ThreadLocal,使用如下:
第一种方式:
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题。
*
* @author
*
*/
public class DateUtil {
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
@SuppressWarnings("rawtypes")
private static ThreadLocal threadLocal = new ThreadLocal() {
protected synchronized Object initialValue() {
return new SimpleDateFormat(DATE_FORMAT);
}
};
public static DateFormat getDateFormat() {
return (DateFormat) threadLocal.get();
}
public static Date parse(String textDate) throws ParseException {
return getDateFormat().parse(textDate);
}
}
创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。
第二种方式:
import java.text.DateFormat;
import java.text.SimpleDateFormat;
/**
* 使用ThreadLocal以空间换时间解决SimpleDateFormat线程安全问题。
*
* @author
*
*/
public class DateUtil {
private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
// 第一次调用get将返回null
private static ThreadLocal threadLocal = new ThreadLocal();
// 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
public static DateFormat getDateFormat() {
DateFormat df = (DateFormat) threadLocal.get();
if (df == null) {
df = new SimpleDateFormat(DATE_FORMAT);
threadLocal.set(df);
}
return df;
}
}
我们看下我们覆盖的initialValue方法:
protected T initialValue() {
return null;//直接返回null
}
第三种方式:
apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效。
分享到:
相关推荐
深入理解Java:SimpleDateFormat安全的时间格式化
NULL 博文链接:https://flynndang.iteye.com/blog/711878
目录SimpleDateFormat诡异bug复现SimpleDateFormat诡异bug字符串日期转Date日期(parse)Date日期转String类型(format)SimpleDateFormat出现...事项使用ThreadLocal解决SimpleDateFormat线程安全问题总结...
高并发之-SimpleDateFormat类的线程安全问题和解决方案.docx
有关SimpleDateFormat的常用方法说明
JavaScript实现的java.text.SimpleDateFormat。希望多多交流。
日期操作。。。基础的SimpleDateFormat格式化日期!!操作!》初级学习代码
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); date.setTime(time); System.out.println(sdf.format(date)); 发现时间于想要的时间不符,请运行Time.reg文件
由浅入深解析 SimpleDateFormat 由浅入深解析 SimpleDateFormat
SimpleDateFormat使用详解。非常实用!!!!
java 使用SimpleDateFormat类获取系统的当前时间 java 使用SimpleDateFormat类获取系统的当前时间
SimpleDateFormat线程不安全的5种解决方案.md
SimpleDateFormat线程不安全的5种解决方案.docx
主要介绍了SimpleDateFormat的线程安全问题与解决方案,非常不错,具有参考借鉴价值,需要的朋友可以参考下
关于SimpleDateFormat的非线程安全问题及其解决方案.docx
1.创建SimpleDateFormat对象,确定日期被格式化的格式 2.使用循环,在循环中调用Thread的sleep方法,让线程休眠1s后打印当前时间的字符串
NULL 博文链接:https://qinchaoyong.iteye.com/blog/543109
NULL 博文链接:https://chaoyi.iteye.com/blog/2082317
主要介绍了Java多线程环境下SimpleDateFormat类安全转换,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧