转自:http://blog.csdn.net/jeamking/article/details/7183958

有时我们在同一个类中都是使用同一种日期格式,又或者为了减少new SimpleDateFormat次数,自然而然的就会出现如下代码:

private static SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");

但是这样做在多线程并发下会存在安全隐患。SimpleDateFormat 类并不是线程同步的,JDK中我们可以看到如下描述:

* Date formats are not synchronized.

* Itis recommended to create separate format instances for each thread.

* Ifmultiple threads access a format concurrently, it must be synchronized

*externally.

下面通过一个简单程序来进行测试:

public class DateUtil {

privatestatic SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");

publicDate parse(String str) throws ParseException{

returnsdf.parse(str);

}

}

public class Test {

/**

* @param args

* @throws InterruptedException

*/

publicstatic void main(String[] args) throws InterruptedException {

SdfRunnablett = new SdfRunnable();

for(inti=0;i<10;i++){

newThread(tt).start();

}

}

}

输出结果:

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Exception in thread "Thread-1"java.lang.NumberFormatException: multiple points

atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

atjava.lang.Double.parseDouble(Unknown Source)

atjava.text.DigitList.getDouble(Unknown Source)

atjava.text.DecimalFormat.parse(Unknown Source)

atjava.text.SimpleDateFormat.subParse(Unknown Source)

atjava.text.SimpleDateFormat.parse(Unknown Source)

atjava.text.DateFormat.parse(Unknown Source)

atDateUtil.parse(DateUtil.java:8)

atSdfRunnable.run(SdfRunnable.java:8)

atjava.lang.Thread.run(Unknown Source)

多运行几次,并不每次都输出这个错误信息,还可能输出如下错误信息:

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Wed Sep 23 12:23:35 CST 2201

Fri Dec 23 12:23:35 CST 2011

Exception in thread "Thread-6"java.lang.NumberFormatException: empty String

atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

atjava.lang.Double.parseDouble(Unknown Source)

atjava.text.DigitList.getDouble(Unknown Source)

atjava.text.DecimalFormat.parse(Unknown Source)

atjava.text.SimpleDateFormat.subParse(Unknown Source)

atjava.text.SimpleDateFormat.parse(Unknown Source)

atjava.text.DateFormat.parse(Unknown Source)

atDateUtil.parse(DateUtil.java:8)

atSdfRunnable.run(SdfRunnable.java:8)

atjava.lang.Thread.run(Unknown Source)

Exception in thread "Thread-1"java.lang.NumberFormatException: For input string: ""

atjava.lang.NumberFormatException.forInputString(Unknown Source)

atjava.lang.Long.parseLong(Unknown Source)

atjava.lang.Long.parseLong(Unknown Source)

atjava.text.DigitList.getLong(Unknown Source)

atjava.text.DecimalFormat.parse(Unknown Source)

atjava.text.SimpleDateFormat.subParse(Unknown Source)

atjava.text.SimpleDateFormat.parse(Unknown Source)Fri Dec 23 12:23:35 CST 2011

atjava.text.DateFormat.parse(Unknown Source)

atDateUtil.parse(DateUtil.java:8)

atSdfRunnable.run(SdfRunnable.java:8)

atjava.lang.Thread.run(Unknown Source)

在以上示例中我们把SimpleDateFormat定义为静态成员的。接下来我们把SimpleDateFormat定义为类普通成员。

public class DateUtil {

privateSimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

publicDate parse(String str) throws ParseException{

returnsdf.parse(str);

}

}

再次运行程序,结果如下:

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

Fri Dec 23 12:23:35 CST 2011

程序运行正常。并没有出现错误信息。那么,是不是意味着SimpleDateFormat作为普通成员就没有安全隐患呢,请看如下示例:

public class SdfRunnable implementsRunnable {

privateSimpleDateFormat sdf;

privateString dateStr;

publicSdfRunnable(SimpleDateFormat sdf,String dateStr){

this.sdf= sdf;

this.dateStr= dateStr;

}

publicvoid run() {

try{

System.out.println(this.sdf.parseObject(this.dateStr));

}catch (ParseException e) {

e.printStackTrace();

}

}

}

public class Test {

/**

* @param args

* @throws InterruptedException

*/

publicstatic void main(String[] args) throws InterruptedException {

SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

SdfRunnablett = new SdfRunnable(sdf,"2011-12-34 12:23:11");

for(inti=0;i<10;i++){

newThread(tt).start();

}

}

}

运行输出结果如下:

Tue Jan 03 12:23:11 CST 2012

Tue Jan 03 12:23:11 CST 2012

Tue Jan 03 12:23:11 CST 2012

Tue Jan 03 12:23:11 CST 2012

Tue Jan 03 12:23:11 CST 2012

Thu Jan 01 00:00:11 CST 1970

Sun Jan 03 12:23:11 CST 1971

Tue Jan 03 12:23:11 CST 2012

Exception in thread "Thread-9"java.lang.NumberFormatException: multiple points

atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

atjava.lang.Double.parseDouble(Unknown Source)

atjava.text.DigitList.getDouble(Unknown Source)

atjava.text.DecimalFormat.parse(Unknown Source)

atjava.text.SimpleDateFormat.subParse(Unknown Source)

atjava.text.SimpleDateFormat.parse(Unknown Source)

atjava.text.DateFormat.parseObject(Unknown Source)

atjava.text.Format.parseObject(Unknown Source)

atSdfRunnable.run(SdfRunnable.java:14)

atjava.lang.Thread.run(Unknown Source)

由此可见,不管是SimpleDateFormat作为静态成员还是成员,在多线程并发下都会存在安全隐患。所以应该在需要使用的地方再new SimpleDateFormat()。

关于SimpleDateFormat非多线程安全问题,在sun的bug database(http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335)中有更多的描述。

SimpleDateFormat做成员或者静态成员多线程安全隐患的更多相关文章

  1. C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)

    知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...

  2. iOS - 互斥锁&&自旋锁 多线程安全隐患(转载)

    一.多线程安全隐患 资源共享  一块资源可能会被多个线程共享,也就是多个线程可能会访问到一块资源 比如多个线程访问同一个对象,同一个变量,同一个文件. 当多线程访问同一块资源的时候,很容易引发数据错乱 ...

  3. JS OOP -04 JS中的公有成员,私有成员和静态成员

    JS中的公有成员,私有成员和静态成员 a.实现类的公有成员 b.实现类的私有成员 c.实现类的静态成员 a.实现类的公有成员 之前定义的任何类型成员都属于公有成员的范畴,该类的任何实例都对外公开这些属 ...

  4. C++类中的常成员和静态成员

    常变量.常对象.常引用.指向常对象或常变量的指针等在定义时都使用了const关键字,这是C++语言引入的一种数据保护机制,称为const数据保护机制.例如通过const关键字主动地将被调函数形参进行限 ...

  5. 精读JavaScript模式(七),命名空间模式,私有成员与静态成员

    一.前言 惰性十足,这篇2月19号就开始写了,拖到了现在,就是不愿意花时间把看过的东西整理一下,其它的任何事都比写博客要有吸引力,我要反省自己. 从这篇开始,是关于JS对象创建模式的探讨,JS语言简单 ...

  6. C++ 静态数据成员和静态成员函数

    一 静态数据成员: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中,因为这样做会引起重复定义这样的错误.即使加上#ifndef ...

  7. js 独立命名空间,私有成员和静态成员

    独立的命名空间   1可以避免全局变量污染. 全局变量污染不是 说 被全局变量污染,而是说不会污染全局变量.   2实现私有成员. 在js中函数 就可以满足独立的命名空间的两点需求.   如:     ...

  8. C# 多线程程序隐患

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  9. C++基础(静态数据成员和静态成员函数)

    [简介] 1.静态数据成员在类中声明,在源文件中定义并初始化: 2.静态成员函数没有this指针,只能访问静态数据成员: 3.调用静态成员函数:(1)对象.(2)直接调用: 4.静态成员函数的地址可用 ...

随机推荐

  1. [vijos P1391] 想越狱的小杉

    考前最后一题,竟然是第一次码SPFA,虽然这个算法早有耳闻,甚至在闻所未闻之前自己有过一个类似的想法,说白了就是广搜啊,但是敲起来还是第一次啊,而且这还不是真正意义上的SPFA. 完全按照自己想法来码 ...

  2. Hive Over HBase

    1. 在hbase上建测试表 hbase(main)::> create 'test_hive_over_hbase','f' row(s) in 2.5810 seconds hbase(ma ...

  3. Mac下同时安装多个版本的JDK & Mac 可设置环境变量的位置、查看和添加PATH环境变量

    http://ningandjiao.iteye.com/blog/2045955 http://elf8848.iteye.com/blog/1582137

  4. RFID Hacking④:使用ProxMark3 破解门禁

    文中提及的部分技术可能带有一定攻击性,仅供安全学习和教学用途,禁止非法使用! 0×00 前言 国际黑客大会Defcon传统之一:开锁!因为黑客认为锁也是一种安全挑战.我们在黑客题材电影.电视剧中也常常 ...

  5. readfile() 函数

    定义和用法 readfile() 函数输出一个文件. 该函数读入一个文件并写入到输出缓冲. 若成功,则返回从文件中读入的字节数.若失败,则返回 false.您可以通过 @readfile() 形式调用 ...

  6. MEDIA-SYSSERVICES媒体播放

    1 简单的音乐播放器 1.1 问题 本案例结合之前所学的网络和数据解析等知识完成一个网络音乐播放器,如图-1所示: 图-1 1.2 方案 首先创建一个SingleViewApplication应用,在 ...

  7. 诺基亚XL中Intent.ACTION_VIEW无效的问题

    今天测试播放视频的时候,发现在诺基亚XL机型里不能弹出视频应用列表. 我的代码是: Intent intent = new Intent(Intent.ACTION_VIEW); intent.set ...

  8. 根据滑动显隐状态栏的iOS实现

    之前很多兄弟问如何实现类似于淘宝客户端搜索列表那种动态显隐的效果,这几天刚好有时间,就实现了几个例子搞一下,其实原理很简单,也参考了github上一位兄弟的实现.不多说,上代码 @interface ...

  9. 第九课,T语言数组的定义与访问(版本5.0)

    数组的定义与访问 数组是一系列数据的集合,可以存储大量数据,通过数组的下标.key,可以实现对数据的快速访问. 为什么要使用数组呢? 如果您有一个项目列表(例如汽车品牌列表),在单个变量中存储这些品牌 ...

  10. Codeforces Round #161 (Div. 2)

    A. Beautiful Matrix 即相当于求1到中心位置\((2,2)\)的曼哈顿距离. B. Squares 排序,取倒数第\(k\)个即可. C. Circle of Numbers 固定\ ...