在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线程非安全的更多相关文章

  1. 如何在一个线程环境中使用一个线程非安全的java类

    在开发过程中 当我们拿到一个线程非安全的java类的时候,我们可以额外创建这个类的管理类 并在管理类中控制同步 比如 一个非线程安全的Pair类 package test.thread.sx.test ...

  2. SimpleDateFormat,Calendar 线程非安全的问题

    SimpleDateFormat是Java中非常常见的一个类,用来解析和格式化日期字符串.但是SimpleDateFormat在多线程的环境并不是安全的,这个是很容易犯错的部分,接下来讲一下这个问题出 ...

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

    前提 这篇文章主要基于JDK11的源码和最近翻看的<深入理解Java虚拟机-2nd>一书的部分内容,对JDK11中的Reference(引用)做一些总结.值得注意的是,通过笔者对比一下JD ...

  4. JDK中线程池参详细解析

    在jdk中为我们提供了三种创建线程池的方式,但是在阿里的编码规范里面都是明确禁止使用这三种api去创建线程池,推荐我们去自定义线程池.为什么? 要回答为什么,我们需要明白创建线程池时,各参数的作用: ...

  5. JDK 中的证书生成和管理工具 keytool

    参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...

  6. VC++ GetModuleFileName()获取路径字符串中带波浪线~

    GetModuleFileName()获取的字符串中带波浪线,不是完整的路径显示. 原因:获取的是短路径,进行了缩写 解决:还原长路径 TCHAR }; GetLongPathName( strTem ...

  7. 深入理解JDK中的I/O

    深入理解JDK中的I/O 目 录 java内存模型GCHTTP协议事务隔离级并发多线程设计模式清楚redis.memcache并且知道区别mysql分表分库有接口幂等性了解jdk8稍微了解一下特性 j ...

  8. C++模拟实现JDK中的ArrayList和LinkedList

    Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...

  9. JDK中的设计模式

    Creational(创建模式) Abstract factory: 创建一组有关联的对象实例.这个模式在JDK中也是相当的常见,还有很多的framework例如Spring.我们很容易找到这样的实例 ...

随机推荐

  1. JUC——延迟队列

    所谓的延迟队列最大的特征是它可以自动通过队列进行脱离,例如:现在有一些对象被临时保存着,但是有可能该集合对象是一个公共对象,那么里面的某些数据如果不在使用的时候就希望其可以在指定的时间达到后自动的消失 ...

  2. phpcms 容许英文目录有空格

    在PHPCMS添加栏目里面,有个选项是 英文目录,这里目录可以用作伪静态功能.这么英文不能有空格等特殊字符.但是如果页面中需要引用包含空格的字符呢,例如,关于我们页面,我要显示英文about us.那 ...

  3. Hadoop源码编译环境搭建

    准备工具: maven 3.0.0版本或者更高版本(配置中心库) protocbuff 2.5.0 http://www.zlib.net/ git bash(Windows环境可以用此工具执行编译命 ...

  4. ngxin 添加模块

    if test -n "$NGX_ADDONS"; then echo configuring additional modules for ngx_addon_dir in $N ...

  5. VMware启动Centos时出现错误Cannot open the disk 'xxxxxxx.vmdk' or one of the snapshot disks it depends on. .

    今天拔装虚拟机的硬盘的时候,没有关掉虚拟机,导致虚拟打开的时候出现:Cannot open the disk 'xxxxxxx.vmdk' or one of the snapshot disks i ...

  6. Mysql Order By注入总结

    何为order by 注入 本文讨论的内容指可控制的位置在order by子句后,如下order参数可控"select * from goods order by $_GET['order' ...

  7. Less 的用法

    1. node.js node.js是一个前端的框架 自带一个包管理工具npm node.js 的安装 官网:http://nodejs.cn/ 在命令行检验是否安装成功 切换到项目目录,初始化了一个 ...

  8. 马赛克是否无法逆转?Python简单消除,看片无忧!

    图片水印,轻松去除 前段时间玩过了全民K歌,不知道大家是否玩过,还是做得挺好的,就我这嗓子都能唱出张学友的味道,其中更是有消除噪声的功能,就是朋友们都在吃鸡大叫,我在旁边唱歌依然不受影响. 既然声音可 ...

  9. 教你用Python解决非平衡数据问题(附代码)

    本文为你分享数据挖掘中常见的非平衡数据的处理,内容涉及到非平衡数据的解决方案和原理,以及如何使用Python这个强大的工具实现平衡的转换. 后台回复“不平衡”获取数据及代码~ 前言 好久没有更新自己写 ...

  10. WPF四则运算《《《《《策略模式

    设计思路:           因为之前没有用过WPF,听说和window窗体语法类似,就想着仿照之前的Window窗体做的,首先用三个textbox存储数据,添加一个comboBox,利用索引选择运 ...