SimpleDateFormat做成员或者静态成员多线程安全隐患
转自: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做成员或者静态成员多线程安全隐患的更多相关文章
- C++学习5-面向对象编程基础(构造函数、转换构造、静态数据成员、静态成员函数、友元)
知识点学习 类 const作用 C语言的const限定符的含义为"一个不能改变值的变量",C++的const限定符的含义为"一个有类型描述的常量": const ...
- iOS - 互斥锁&&自旋锁 多线程安全隐患(转载)
一.多线程安全隐患 资源共享 一块资源可能会被多个线程共享,也就是多个线程可能会访问到一块资源 比如多个线程访问同一个对象,同一个变量,同一个文件. 当多线程访问同一块资源的时候,很容易引发数据错乱 ...
- JS OOP -04 JS中的公有成员,私有成员和静态成员
JS中的公有成员,私有成员和静态成员 a.实现类的公有成员 b.实现类的私有成员 c.实现类的静态成员 a.实现类的公有成员 之前定义的任何类型成员都属于公有成员的范畴,该类的任何实例都对外公开这些属 ...
- C++类中的常成员和静态成员
常变量.常对象.常引用.指向常对象或常变量的指针等在定义时都使用了const关键字,这是C++语言引入的一种数据保护机制,称为const数据保护机制.例如通过const关键字主动地将被调函数形参进行限 ...
- 精读JavaScript模式(七),命名空间模式,私有成员与静态成员
一.前言 惰性十足,这篇2月19号就开始写了,拖到了现在,就是不愿意花时间把看过的东西整理一下,其它的任何事都比写博客要有吸引力,我要反省自己. 从这篇开始,是关于JS对象创建模式的探讨,JS语言简单 ...
- C++ 静态数据成员和静态成员函数
一 静态数据成员: 1.静态数据成员的定义. 静态数据成员实际上是类域中的全局变量.所以,静态数据成员的定义(初始化)不应该被放在头文件中,因为这样做会引起重复定义这样的错误.即使加上#ifndef ...
- js 独立命名空间,私有成员和静态成员
独立的命名空间 1可以避免全局变量污染. 全局变量污染不是 说 被全局变量污染,而是说不会污染全局变量. 2实现私有成员. 在js中函数 就可以满足独立的命名空间的两点需求. 如: ...
- C# 多线程程序隐患
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- C++基础(静态数据成员和静态成员函数)
[简介] 1.静态数据成员在类中声明,在源文件中定义并初始化: 2.静态成员函数没有this指针,只能访问静态数据成员: 3.调用静态成员函数:(1)对象.(2)直接调用: 4.静态成员函数的地址可用 ...
随机推荐
- MSSQL常用函数
declare 定义变量 set 为变量赋值 SUBSTRING()函数 SUBSTRING ( expression, start, length ) expression 字符串.二进制字符串.文 ...
- Galaxy Classification
10.3 Data Preparation After removing a large number of the columns from the raw SDSS dataset, introd ...
- Java类与对象——几个课堂例子的总结及作业
作业:使用类的静态字段和构造函数,我们可以跟踪某个类所创建对象的个数.请写一个类,在任何时候都可以向它查询“你已经创建了多少个对象?”. 源代码: import java.util.Scanner; ...
- uoot启动过程
1.从我们的start_armboot开始讲起 u-boot整体由汇编段和C语言段外加连接脚本组成.关于汇编段请看我之前的博客<u-boot源码汇编段简要分析>,好,让我们进入start_ ...
- 在 Sublime Text 2 中使用 SFTP 插件快速编辑远程服务器文件
在 Sublime Text 2 中使用 SFTP 插件快速编辑远程服务器文件 开源程序 浏览:29555 2013年05月02日 文章目录[隐藏] 常见的工作流程 SFTP 安装和使用方法 第一步: ...
- UE4 在C++ 动态生成几何、BSP体、Brush ---- Mesh_Generation
截至UE4 4.10 runtime 无法生成BSP类 ,只能通过自定义的Mesh的Vertex 进行绘制 ( Google 考证,能改UE4源码的请忽略 ) 可用到的 UE4 集成的Render ...
- wndows程序设计之书籍知识与代码摘录-封装一个类似printf的messagebox
//----------------------------------------- //本程序展示了如何实现MessageBoxPrintf函数 //本函数能像printf那样格式化输出 //摘录 ...
- SVN小贴士
我辛辛苦苦写的到哪里了? SVN小贴士SVN服务器上的代码项目组公用,你的每一个提交都会体现给项目组每个人,所以提交要慎重,要注意避免代码冲突,使用SVN小贴士: 1.提前宣布开发计划,保持项目组成员 ...
- 1、c#对XML文件的解析
1.XML文件 <?xml version="1.0" encoding="utf-8"?> <PersonF xmlns="&qu ...
- 从零开始学习Node.js例子七 发送HTTP客户端请求并显示响应结果
wget.js:发送HTTP客户端请求并显示响应的各种结果 options对象描述了将要发出的请求.data事件在数据到达时被触发,error事件在发生错误时被触发.HTTP请求中的数据格式通过MIM ...