关于SimpleDateFormat的线程安全问题和解决方案
程序员文章站
2022-05-25 14:45:37
...
首先简单说一下SimpleDateFormat存在线程安全问题的原因。SimpleDateFormat继承了DateFormat类,类中有一个受保护类型的Calendar对象,再看一下SimpleDateFormat的format方法:
private StringBuffer format(Date date, StringBuffer toAppendTo,
FieldDelegate delegate) {
// Convert input date to time field list
calendar.setTime(date);
boolean useDateFormatSymbols = useDateFormatSymbols();
for (int i = 0; i < compiledPattern.length; ) {
int tag = compiledPattern[i] >>> 8;
int count = compiledPattern[i++] & 0xff;
if (count == 255) {
count = compiledPattern[i++] << 16;
count |= compiledPattern[i++];
}
......
}
相信大家看到标红的这行代码时,都会明白为什么format方法是非线程安全的了。多个线程共享SimpleDateFormat实例时,对Calendar对象的更改会相互影响,因此产生了线程安全问题。
OK,解决方案:
1、每当使用时创建一个SimpleDateFormat的实例,但性能会较差(其实以现在jdk的优异表现和软硬件性能的提升,创建SimpleDateFormat实例对性能的影响并不是很明显)。
2、使用ThreadLocal避免多线程共享实例,代码:
public class ConcurrentDateUtil { private static ThreadLocal<DateFormat> DateThreadLocal = new ThreadLocal<DateFormat>() { protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd"); } }; private static ThreadLocal<DateFormat> DateTimeThreadLocal = new ThreadLocal<DateFormat>() { protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static Date parseDate(String dateStr) throws ParseException { return DateThreadLocal.get().parse(dateStr); } public static String formatDate(Date date) { return DateThreadLocal.get().format(date); } public static Date parseDateTime(String dateStr) throws ParseException { return DateTimeThreadLocal.get().parse(dateStr); } public static String formatDateTime(Date date) { return DateTimeThreadLocal.get().format(date); } }
3、一些其他的方法,比如使用synchronized或第三方工具类,前者对性能影响较大,后者不在本文讨论范围内,大家有时间可以自行研究。
上一篇: 转:SimpleDateFormat24小时制时间显示
下一篇: MySQL 数据库通过日志恢复