博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
SimpleDateFormat 的使用注意点(线程安全问题)
阅读量:5971 次
发布时间:2019-06-19

本文共 3761 字,大约阅读时间需要 12 分钟。

hot3.png

Bug: Call to method of static .text.DateFormat

Pattern id: STCAL_INVOKE_ON_STATIC_DATE_FORMAT_INSTANCE, type: STCAL, category: MT_CORRECTNESS

As the JavaDoc states, DateFormats are inherently unsafe for multithreaded use. The detector has found a call to an instance of DateFormat that has been obtained via a static field. This looks suspicous.

For more information on this see Sun Bug #6231579 and Sun Bug #6178997.

 

    上面的英文解释其实应该说得比较清楚,在Java文档中,已经明确说明了DateFormats 是非线程安全的,而在SimpleDateFormat的Jdk 的Source文件中,我们也找到这么一段注释,说明它不是线程安全的。

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

在Sun自己的网站上。在sun的bug database中,Sun Bug #6231579 ,Sun Bug #6178997都可以印证这个问题。

    导致SimpleDateFormat出现多线程安全问题的原因,是因为:SimpleDateFormat处理复杂,Jdk的实现中使用了成员变量来传递参数,这就造成在多线程的时候会出现错误。

    而Findbugs所说的“Call to static DateFormat”,其实就是一些人:为了渐少new 的次数而把SimpleDateFormat做成成员或者静态成员,上面已经说了,这样做是不安全的。

    其实,出现这种问题的代码一般都长得差不多,典型的代码示例如下:

public class Test {	private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");	public void method1() {		dateFormat.format(new Date());	}	public void method2() {		dateFormat.format(new Date());	}}

再给个详细例子说明问题,看下面代码:

import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;public class Test {	private SimpleDateFormat dateFormat;	public static void main(String[] args) {		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");		Date today = new Date();		Date tomorrow = new Date(today.getTime() + 1000 * 60 * 60 * 24);		System.out.println(today); // 今天是2010-01-11		System.out.println(tomorrow); // 明天是2010-01-11		Thread thread1 = new Thread(new Thread1(dateFormat, today));		thread1.start();		Thread thread2 = new Thread(new Thread2(dateFormat, tomorrow));		thread2.start();	}}class Thread1 implements Runnable {	private SimpleDateFormat dateFormat;	private Date date;	public Thread1(SimpleDateFormat dateFormat, Date date) {		this.dateFormat = dateFormat;		this.date = date;	}	public void run() {		for (;;) {// 一直循环到出问题为止吧。			String strDate = dateFormat.format(date);			// 如果不等于2010-01-11,证明出现线程安全问题了!!!!			if (!"2010-01-11".equals(strDate)) {				System.err.println("today=" + strDate);				System.exit(0);			}		}	}}class Thread2 implements Runnable {	private SimpleDateFormat dateFormat;	private Date date;	public Thread2(SimpleDateFormat dateFormat, Date date) {		this.dateFormat = dateFormat;		this.date = date;	}	public void run() {		for (;;) {			String strDate = dateFormat.format(date);			if (!"2010-01-12".equals(strDate)) {				System.err.println("tomorrow=" + strDate);				System.exit(0);			}		}	}}

运行的结果如下:

Mon Jan 11 11:30:36 CST 2010Tue Jan 12 11:30:36 CST 2010tomorrow=2010-01-11

终于看到问题了,tomorrow=2010-01-11,错得很明显了。其实要避免这个问题方法很简单,不使用SimpleDateFormat,或者不使用成员变量/静态成员变量的SimpleDateFormat对象即可。

以上出自: 

解决办法:使用org.apache.commons.lang.time.DateFormatUtils,示例:

private final static String YYYY = "yyyy";	private final static String sdfDay = "yyyy-MM-dd";	private final static String sdfDays = "yyyyMMdd";	private final static String sdfTime = "yyyy-MM-dd HH:mm:ss";	/**	 * 获取YYYY格式	 * 	 * @return	 */	public static String getYear() {		return DateFormatUtils.format(new Date(), YYYY);	}	/**	 * 获取YYYY-MM-DD格式	 * 	 * @return	 */	public static synchronized String getDay() {		return DateFormatUtils.format(new Date(), sdfDay);	}	/**	 * 获取YYYYMMDD格式	 * 	 * @return	 */	public static synchronized String getDays() {		return DateFormatUtils.format(new Date(), sdfDays);	}	/**	 * 获取YYYY-MM-DD HH:mm:ss格式	 * 	 * @return	 */	public static synchronized String getTime() {		return DateFormatUtils.format(new Date(), sdfTime);	}

 

转载于:https://my.oschina.net/ydsakyclguozi/blog/677011

你可能感兴趣的文章
php正则怎么使用(最全最细致)
查看>>
javascript数学运算符
查看>>
LC.155. Min Stack(非优化,两个stack 同步 + -)
查看>>
交互设计[3]--点石成金
查看>>
SCCM TP4部署Office2013
查看>>
SVN: bdb: BDB1538 Program version 5.3 doesn't match environment version 4.7
查看>>
jsp内置对象作业3-application用户注册
查看>>
android115 自定义控件
查看>>
iOS uuchart 用法
查看>>
c# 多线程 调用带参数函数
查看>>
JQuery 如何选择带有多个class的元素
查看>>
The absolute uri: http://java.sun.com/jsp/jstl/core cannot be resolved in either web.xml or the jar
查看>>
redis主从配置<转>
查看>>
karma如何与测试框架合作2之webpack
查看>>
10分钟搭建MySQL Binlog分析+可视化方案
查看>>
vmware虚拟机配置串口
查看>>
小型自动化运维--expect脚本之传递函数
查看>>
Nsrp实现juniper防火墙的高可用性【HA】!
查看>>
oracle11g 安装在rhel5.0笔记
查看>>
解决Lync 2013演示PPT提示证书问题的多种方法
查看>>