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线程非安全的更多相关文章
- 如何在一个线程环境中使用一个线程非安全的java类
在开发过程中 当我们拿到一个线程非安全的java类的时候,我们可以额外创建这个类的管理类 并在管理类中控制同步 比如 一个非线程安全的Pair类 package test.thread.sx.test ...
- SimpleDateFormat,Calendar 线程非安全的问题
SimpleDateFormat是Java中非常常见的一个类,用来解析和格式化日期字符串.但是SimpleDateFormat在多线程的环境并不是安全的,这个是很容易犯错的部分,接下来讲一下这个问题出 ...
- 深入理解JDK中的Reference原理和源码实现
前提 这篇文章主要基于JDK11的源码和最近翻看的<深入理解Java虚拟机-2nd>一书的部分内容,对JDK11中的Reference(引用)做一些总结.值得注意的是,通过笔者对比一下JD ...
- JDK中线程池参详细解析
在jdk中为我们提供了三种创建线程池的方式,但是在阿里的编码规范里面都是明确禁止使用这三种api去创建线程池,推荐我们去自定义线程池.为什么? 要回答为什么,我们需要明白创建线程池时,各参数的作用: ...
- JDK 中的证书生成和管理工具 keytool
参考资料 该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference .Oracle 在 Java 方面的文档是非常完善的.对 Java 8 感兴趣的朋友,可以直接找 ...
- VC++ GetModuleFileName()获取路径字符串中带波浪线~
GetModuleFileName()获取的字符串中带波浪线,不是完整的路径显示. 原因:获取的是短路径,进行了缩写 解决:还原长路径 TCHAR }; GetLongPathName( strTem ...
- 深入理解JDK中的I/O
深入理解JDK中的I/O 目 录 java内存模型GCHTTP协议事务隔离级并发多线程设计模式清楚redis.memcache并且知道区别mysql分表分库有接口幂等性了解jdk8稍微了解一下特性 j ...
- C++模拟实现JDK中的ArrayList和LinkedList
Java实现ArrayList和LinkedList的方式采用的是数组和链表.以下是用C++代码的模拟: 声明Collection接口: #ifndef COLLECTION_H_ #define C ...
- JDK中的设计模式
Creational(创建模式) Abstract factory: 创建一组有关联的对象实例.这个模式在JDK中也是相当的常见,还有很多的framework例如Spring.我们很容易找到这样的实例 ...
随机推荐
- Java Comparator接口学习笔记
Comparator是一个泛型函数式接口,T表示待比较对象的类型: @FunctionalInterface public interface Comparator<T> { } 本文将主 ...
- 你这一辈子要用到的C数学函数都在这
两数相加 #include <stdio.h> int main(void){ int a = 10; //定义变量a, 把10 赋值给a int b = 20; //定义变量 ...
- 如何判断Map中的key或value是什么类型
在上班写工具类时,遇到了一个问题,将xml文件的节点都放入map容器中时,map的value也是一个map,导致取map的value时,需要判断这个value的数据类型,用到了一下说的这些知识: 对于 ...
- linux获得命令使用帮助
1. 内部命令: help CMD 2. 外部命令: CMD --help 3. 命令手册: manual(所有命令) man CMD 分章节: 1: 用户命令(User Commands - /bi ...
- 《Spring2之站立会议8》
<Spring2之站立会议8> 昨天,添加了登录界面: 今天,准备添加注册界面: 遇到的问题:过程中遇到了一些困难,不过还是解决了.
- ORACLE中的异常处理
异常的语法格式 在begin语句内: exception when then when then when others then --异常处理 --首先创建一份对象的用法 create type x ...
- 进阶系列(2)—— C#集合
一.集合介绍 集合是.NET FCL(Framework Class Library)的重要组成部分,我们平常撸C#代码时免不了和集合打交道,FCL提供了丰富易用的集合类型,给我们撸码提供了极大的便利 ...
- Leetcode题库——17.电话号码的字母组合
@author: ZZQ @software: PyCharm @file: letterCombinations.py @time: 2018/10/18 18:33 要求:给定一个仅包含数字 2- ...
- NABCD(网上投票系统)
网上投票系统 N(need) 投票这件事情,在所有事情上都可能用得到,在互联网的影响下,投票的范围变得越来越广,比如在商业的里,往往要做市场分析,那么在互联网这个大的前提下,用网上投票系统来获取用户的 ...
- 【动态规划】POJ-3176
一.题目 Description The cows don't use actual bowling balls when they go bowling. They each take a numb ...