SimpleDateFormat线程不安全原因及解决方案
Posted yangyongjie
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SimpleDateFormat线程不安全原因及解决方案相关的知识,希望对你有一定的参考价值。
线程不安全验证:
/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() while (true) poolExecutor.execute(new Runnable() @Override public void run() String dateString = simpleDateFormat.format(new Date()); try Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); catch (ParseException e) e.printStackTrace(); );
输出:
true
false
true
true
false
出现了false,说明线程不安全
1、format方法
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); // Called from Format after creating a FieldDelegate 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++]; switch (tag) case TAG_QUOTE_ASCII_CHAR: toAppendTo.append((char)count); break; case TAG_QUOTE_CHARS: toAppendTo.append(compiledPattern, i, count); i += count; break; default: subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols); break; return toAppendTo;
protected Calendar calendar;
可以看到,多个线程之间共享变量calendar,并修改calendar,因此在多线程环境下,线程是不安全的。
解决方案:
1、将SimpleDateFormat定义成局部变量
2、 加一把线程同步锁:synchronized(lock)
3、使用ThreadLocal,每个线程都拥有自己的SimpleDateFormat对象副本
如:
/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest ThreadLocal<SimpleDateFormat> local = new ThreadLocal<>(); // private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() while (true) poolExecutor.execute(new Runnable() @Override public void run() SimpleDateFormat simpleDateFormat = local.get(); if (simpleDateFormat == null) simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String dateString = simpleDateFormat.format(new Date()); try Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); catch (ParseException e) e.printStackTrace(); );
4、使用DateTimeFormatter代替SimpleDateFormat
以上是关于SimpleDateFormat线程不安全原因及解决方案的主要内容,如果未能解决你的问题,请参考以下文章
Java Review - SimpleDateFormat线程不安全原因的源码分析及解决办法
还在用 SimpleDateFormat 做时间格式化?小心项目崩掉!