在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. jmeter功能按钮介绍

    Jmeter本来是做性能测试的,所以有很多监听器都是针对性能的,随后边的不断发展,可以应用到接口自动化等测试工作上. 面板的文件菜单中一般都是打开.保存.新建测试的,如下图: 保存时可以直接ctrl+ ...

  2. 学习python,第四篇:Python 3中bytes/string的区别

    原文:http://eli.thegreenplace.net/2012/01/30/the-bytesstr-dichotomy-in-python-3 python 3中最重要的新特性可能就是将文 ...

  3. docker实现跨主机连接

    实验环境: centos7系统 host1:192.168.42.128 host2:192.168.42.129 dokcer容器跨主机连接 1.使用网桥实现跨主机容器连接 2.使用Open vSw ...

  4. salt-api https连接问题

    在非salt-api的主机上测试api连通性,测试代码如下: #!/usr/bin/env python import pycurl import StringIO import ssl ssl._c ...

  5. [朴孝敏][Sketch]

    歌词来源:http://music.163.com/#/song?id=406907303 作曲 : Ryan S. Jhun/August Rigo/Denzil Remedios [作曲 : Ry ...

  6. python处理数据pandas视频资料

    python强大数据处理工具pandas视频资料:https://pan.baidu.com/s/17VRd1cgFaKi20drfCgZ8Gg

  7. SE Springer小组《Spring音乐播放器》可行性研究报告一、二

    1 引言 1.1编写目的 <软件工程>课程,我们团队计划开发一个音乐播放器.本文档是基于网络上现有的音乐播放器的特点,团队计划实现的音乐播放器功能和团队人员的综合实力等情况,说明该软件开发 ...

  8. 一个简单的加减乘除自动生成小程序(JAVA)

    在学习软件工程的时候,遇到一个这样的问题,一个程序员的儿子上小学二年级,老师让家长每天出30道加减题目给学生做,由于家长是个程序员,所以呢,他就自己写了个程序实现,我们可爱的老师于是也叫我们写了一个类 ...

  9. DPDK RX / TX Callbacks 源码阅读

    这个sample是基于basicfw的.basicfw就是一个网口收到的包立即从另一个网口转发出去,非常简洁明了的程序,可以通过basicfw学习基础的DPDK发包API.RX / TX Callba ...

  10. Software Defined Networking(Week 3, part 1)

    Control and Data Plane Seperation 课程地址 Overview 今天正式地学习一个控制与数据平面分离.学习完本节,应该要掌握何为控制和数据平面,了解它们的功能以及好处, ...