JDK中的SimpleDateFormat线程非安全

  在JDK中使用SimpleDateFormat的时候都会遇到线程安全的问题,在JDK文档中也说明了该类是线程非安全的,建议对于每个线程都创建一个SimpleDateFormat对象。如下面一个Case中,多个线程去调用SimpleDateFormat中得parse方法:


@Test
public void testUnThreadSafe() throws Exception {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");

final String[] dateStrings = {
"2014-04-30 18:51:01,61",
"2014-04-30 18:51:01,461",
"2014-04-30 18:51:01,361",
"2014-04-30 18:51:01,261",
"2014-04-30 18:51:01,161",
};
int threadNum = 5;
Thread[] parseThreads = new Thread[threadNum];
for (int i=0; i<threadNum; i++) {
parseThreads[i] = new Thread(new Runnable() {
public void run() {
for (int j=0; j<dateStrings.length; j++) {
try {
System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
parseThreads[i].start();
}

for (int i=0; i<threadNum; i++) {
parseThreads[i].join();
}
}

将会抛出异常:java.lang.NumberFormatException: multiple points

通常的解决办法有:

1. 使用synchronized


synchronized (sdf) {
  System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
}

2. 每用一次实例化一次


try {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
} catch (ParseException e) {
e.printStackTrace();
}

3. 使用ThreadLocal


    @Test
public void testUnThreadSafe() throws Exception {
// final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
final ThreadLocal<SimpleDateFormat> localSdf = new ThreadLocal<SimpleDateFormat>();
final String[] dateStrings = {
"2014-04-30 18:51:01,61",
"2014-04-30 18:51:01,461",
"2014-04-30 18:51:01,361",
"2014-04-30 18:51:01,261",
"2014-04-30 18:51:01,161",
};
int threadNum = 5;
Thread[] parseThreads = new Thread[threadNum];
for (int i=0; i<threadNum; i++) {
parseThreads[i] = new Thread(new Runnable() {
public void run() {
for (int j=0; j<dateStrings.length; j++) {
try {
SimpleDateFormat sdf = localSdf.get();
if (sdf == null) {
sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
localSdf.set(sdf);
}
System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
});
parseThreads[i].start();
}

for (int i=0; i<threadNum; i++) {
parseThreads[i].join();
}
}

第一种和第二种解决方案对于一个工具类来说都会带来昂贵的资源开销,建议使用ThreadLocal创建一个对单个线程来说全局的变量,保证线程安全,当然可以使用第三方工具类如Apache
commons 里的FastDateFormat或者Joda-Time类库来处理。

JDK中的SimpleDateFormat线程非安全,码迷,mamicode.com

时间: 2024-12-25 16:03:29

JDK中的SimpleDateFormat线程非安全的相关文章

SimpleDateFormat,Calendar 线程非安全的问题

SimpleDateFormat是Java中非常常见的一个类,用来解析和格式化日期字符串.但是SimpleDateFormat在多线程的环境并不是安全的,这个是很容易犯错的部分,接下来讲一下这个问题出现的过程以及解决的思路. 问题描述:先看代码,用来获取一个月的天数的: import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class DateUtil { /** *

深入理解JDK中的Reference原理和源码实现

前提 这篇文章主要基于JDK11的源码和最近翻看的<深入理解Java虚拟机-2nd>一书的部分内容,对JDK11中的Reference(引用)做一些总结.值得注意的是,通过笔者对比一下JDK11和JDK8对于java.lang.ref包的相关实现,发现代码变化比较大,因此本文的源码分析可能并不适合于JDK11之外的JDK版本. Reference的简介和分类 在JDK1.2之前,Java中的引用的定义是十分传统的:如果reference类型的数据中存储的数值代表的是另一块内存的起始地址,就称这

jdk 中Runtime之单例模式 学习

这段代码是我从源码中截取的,大家很容易看到currentRuntime是一个静态变量,getRunTime对应的就是getInstacne.不是说这种方法不好吗? 1 public class Runtime { 2 45 private static Runtime currentRuntime = new Runtime(); 3 4 5 Returns the runtime object associated with the current Java application. Most

JDK中的Timer和TimerTask详解

目录结构: Timer和TimerTask 一个Timer调度的例子 如何终止Timer线程 关于cancle方式终止线程 反复执行一个任务 schedule VS. scheduleAtFixedRate 一些注意点 1. Timer和TimerTask Timer是jdk中提供的一个定时器工具,使用的时候会在主线程之外起一个单独的线程执行指定的计划任务,可以指定执行一次或者反复执行多次. TimerTask是一个实现了Runnable接口的抽象类,代表一个可以被Timer执行的任务. 2.

WebService之JDK中wsimport命令

1.编写WebService类,使用@WebService注解 package test; import javax.jws.WebService; @WebService public class HelloServiceImpl{ public String say(String name) { return "Hello "+name; } } WebService类 2.使用main方法发布WebService package test; import javax.xml.ws

Jdk中的设计模式

转自:http://blog.csdn.net/gtuu0123/article/details/6114197 本文主要是归纳了JDK中所包含的设计模式,包括作用和其设计类图.首先来个总结,具体的某个模式可以一个一个慢慢写,希望能对研究JDK和设计模式有所帮助. 一.设计模式是什么(1)反复出现问题的解决方案(2)增强软件的灵活性(3)适应软件不断变化 二.学习JDK中设计模式的好处(1)借鉴优秀代码的设计,有助于提高代码设计能力(2)JDK的设计中体现了大多数设计模式,是学习设计模式的较好的

1.5Java语言(JDK中的命令行工具)

1.3.4 配置环境变量path(1)  在dos命令行中敲入javac,出现错误提示.  错误原理:当前执行的程序在当前目录下如果不存在,windows系统会在系统中已有的一个名为path的环境变量指定的目录中查找.如果还没有找到,就出现以上的错误提示.  所以进入到jdk安装路径\bin目录下,执行javac.看到javac参数提示信息. 1.5Java语言(JDK中的命令行工具),布布扣,bubuko.com

JDK中的URLConnection参数详解

JDK中的URLConnection参数详解 来自:http://www.blogjava.net/supercrsky/articles/247449.html 针对JDK中的URLConnection连接Servlet的问题,网上有虽然有所涉及,但是只是说明了某一个或几个问题,是以FAQ的方式来解决的,而且比较零散,现在对这个类的使用就本人在项目中的使用经验做如下总结: 1:> URL请求的类别: 分为二类,GET与POST请求.二者的区别在于:      a:) get请求可以获取静态页面

JDK中Integer类的进制转换实现

JDK中关于Integer类的进制转换方法很精巧,具体实现如下: final static char[] digits = { '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' , 'u' ,