- 浏览: 804554 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
huan19900606:
像haskell这些脚本语言很容易定义DSL,实现对应的词法语 ...
DSL的基本介绍(groovy来进行构建) -
express_wind:
https://yq.aliyun.com/album/130 ...
qlexpress规则引擎初探 -
readxuxuegang:
博主你好。如果groovy的代码是保存在数据库里,不是文件,这 ...
在java中使用groovy怎么搞 (java and groovy) -
express_wind:
hi,兄弟,有没有兴趣来阿里巴巴专门做这方面的研究,https ...
qlexpress规则引擎初探 -
langcaiye:
有2个问题请教:1. 这里的base32算法为什么需要以负数的 ...
【原】geohash算法详解
在多线程情况下使用SimpleDateFormat要尤其注意,它不是线程安全的。问题是一个老问题,但是经常出现。
在java的api中这样描述:
“Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.”
这个类一个典型的场景是按照指定的格式,将日期类型数据转换为字符串类型,或者将字符串类型转换为日期类型。
(1)多线程场景,在方法体内部new DateFormat对象,但是这种情况对于内存开销比较大,同时对于一些可以复用的格式,重复来拷贝代码看起来有点恶心;
(2)通过synchronize机制,但是线程同步同样会造成性能下降;
(3)到通过静态工厂方法例如“getDateInstance”来创建DateFormat的对象,这种方法看起来很有效,但是由于在DateFormat中缺乏同步,所以在多线程获取同一个对象的时候会出现问题,典型的异常有NumberFormatExcetion和ArrayIndexOutOfBoundsException;
(4)通过ThreadLocal来搞定;
(5)使用第三方工具包,例如apache-common的DateFormatUtils;
A、首先模拟一个线程安全问题
在用到format的时候,我们经常在方法中new一个对象,SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");但是有时候,我们为了省事和复用,把这个对象作为静态对象来抽取出来,但是这样是有问题的,线程不安全。
下面这个例子,SimpleDateFormat的对象是静态类,所以执行结果的时候就出现错乱的情况了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
|
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class SimpleTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool( 10 );
for ( int i= 0 ;i< 30 ;i++){
threadPool.submit( new TestSimpleThread( new Date( 2012 , 11 ,i),i));
}
}
} class TestSimpleThread implements Runnable{
private static SimpleDateFormat sf = new SimpleDateFormat( "yyyy-MM-dd" );
private Date date;
private int temp;
public TestSimpleThread(Date d, int t){
date = d;
temp = t;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+ "---" +temp+ "---" +sf.format(date));
}
} |
按照我们的设计,两列值如果线程安全,那应该是相同的,但是执行的时候出现了错误。
B、上面SimpleDateFormat是类的静态属性,通过加锁能够解决这个问题,下面例子跑出来的结果是正常的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.junit.Test;
public class SimpleTest {
public static void main(String[] args) {
ExecutorService threadPool = Executors.newFixedThreadPool( 10 );
for ( int i= 0 ;i< 30 ;i++){
threadPool.submit( new TestSimpleThread( new Date( 2012 , 11 ,i),i));
}
}
} class TestSimpleThread implements Runnable{
private static SimpleDateFormat sf = new SimpleDateFormat( "yyyy-MM-dd" );
public String convertDateToString(Date d) throws Exception {
String result;
synchronized (sf) {
result = sf.format(d);
}
return result;
}
private Date date;
private int temp;
public TestSimpleThread(Date d, int t){
date = d;
temp = t;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName()+ "---" +temp+ "---" +convertDateToString(date));
} catch (Exception e) {
//
}
}
} |
在进行format的时候加了同步:
C、通过 SimpleDateFormat.getDateInstance()来获取对象进行操作,没有还原上面说的场景,但是发现一个问题,就是里面的参数是int类型,如果想灵活的进行自定义格式,用起来不是很方便。
D、采用ThreadLocal的方式来解决线程安全问题
下面这个是通过覆盖initialValue方法,
1
2
3
4
5
6
7
8
9
10
11
12
|
public class ThreadLocalSF {
private static ThreadLocal<DateFormat> threadDateFormatDefault = new ThreadLocal<DateFormat>(){
@Override
protected DateFormat initialValue() {
return new SimpleDateFormat( "yyyy-MM-dd" );
}
};
public static String convertDateToString(Date d) {
return threadDateFormatDefault.get().format(d);
}
} |
还有一中就是 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class DateUtil { private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss" ;
// 第一次调用get将返回null
private static ThreadLocal threadLocal = new ThreadLocal();
// 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
public static DateFormat getDateFormat() {
DateFormat df = (DateFormat) threadLocal.get();
if (df == null ) {
df = new SimpleDateFormat(DATE_FORMAT);
threadLocal.set(df);
}
return df;
}
} |
网上有张图对于三种方式的TPS做了对比,性能最好的是ThreadLocal的方式。
看了一些公共的DateUtil类,基本上采用的最简单的模式:
写一个静态类DateUtil,里面搞一个静态方法,每个方法内部new一个SimpleDateFormat的类,然后进行调用,这种最简单呵呵。
参考:http://www.javacodegeeks.com/2010/07/java-best-practices-dateformat-in.html
发表评论
-
系统分布式情况下最终一致性方案梳理
2015-09-05 19:34 40934前言 目前的应用系 ... -
Storm核心概念剖析
2015-03-20 20:42 3220最近团队中有分析的场 ... -
池和流的两种数据处理方式
2014-11-19 22:59 1379在抽象层面,想了一下,目前很多的数据处理形式,一般分为池和流 ... -
关于CodeReview(java)
2014-10-29 20:42 1894关于codereview,在平时的开发中,经常忽略的环节,参 ... -
java中各种各样的数据结构
2014-07-13 20:26 2455在java中,有非常丰富的数据结构,可能是因为大多数的软件 ... -
关于JVM的ClassLoader(笔记)
2014-07-13 12:19 1859众所周知,java是编译型的语言,写的是java文 ... -
关于事务的几个概念介绍
2014-06-06 22:22 1935啥是事务? 有一组操 ... -
开发中遇到的编码问题
2014-05-22 19:39 18701、说到编码,最大的问题就是乱码了,为啥会有乱码呢 ? 因 ... -
ThreadLocal源代码解析
2014-04-24 17:54 2399最开始的时候,理解的ThreadLocal,我的理解是这样的 ... -
关于单例模式(代码篇)
2014-04-23 10:47 2411很早的时候,转发过一篇单例模式的文章:http://iamz ... -
今天遇到的两个spring相关的两个问题
2014-04-18 21:56 2550今天在项目中写代码,遇到两个Spring的问题,记录一下。再 ... -
Activiti中的命令模式解析
2014-04-11 13:10 3176最近在看Activiti的源代码,发现是基于命令模式进行的开 ... -
关于java中的本地缓存-总结概述
2014-03-31 19:00 18355java中的本地缓存,工作后陆续用到,一直想写,一直无从下 ... -
使用guava中的EventBus构建内存级别的事件引擎
2014-03-25 19:27 6392这个EventBus是guava中比较给力的一个类,从字面 ... -
DSL的基本介绍(groovy来进行构建)
2014-03-04 23:32 17034什么是DSL? 领域特定 ... -
qlexpress规则引擎初探
2014-02-25 22:28 25071qlexpress是啥? 这个是阿里内部的一个开源的jav ... -
在java中使用groovy怎么搞 (java and groovy)
2014-01-15 23:17 10937什么是groovy? 一种基于Java虚拟机的动态语言, ... -
java中记录方法调用时间,结果按照方法的层级树状的输出
2013-12-21 17:36 4669 在java中,最常用的埋点时间的方法就 ... -
一次CMS GC问题排查过程(理解原理+读懂GC日志)
2013-12-14 22:21 41334这个是之前处理过的一个线上问题,处理过程断断续续,经历了两 ... -
令牌桶算法和漏桶算法以及流量控制浅谈
2013-11-27 23:20 20770 在双十一等大促环节,系统需要限流,外部 ...
相关推荐
4. 避免在多线程环境中直接使用HashMap:如果你确定不需要在多线程环境下共享HashMap,那么可以考虑局部变量的方式,只在单个线程中使用HashMap,这样就无需担心线程安全问题。 总结起来,理解HashMap的线程不安全...
内容概要:文章内容从原子性、可见性、有序性三个方面介绍C++线程安全问题的原因。通过原子操作、线程同步如互斥锁、读写锁、条件变量、信号量等方法解决C++线程安全问题。同时介绍了线程安全的单例,饿汉模式和懒汉...
浅谈C#跨线程调用窗体控件引发的线程安全问题 C#跨线程调用窗体控件时可能会引发线程安全问题,例如当多个线程操作同一个控件时,该控件可能会进入不一致的状态,出现争用情况和死锁等问题。因此,确保以线程安全...
本篇文章将深入探讨“最简单的线程安全问题”,并结合相关源码和工具来帮助理解。线程安全问题通常涉及到多个线程对共享资源的访问,如果管理不当,可能会导致数据不一致、死锁等问题。 首先,我们需要了解什么是...
多线程编程带来的并发执行是其与生俱来的优势,但同时也引入了一系列的问题,尤其是线程安全问题。 线程安全问题主要来源于多个线程对共享资源的访问。如果多个线程同时访问同一个资源,且没有适当的同步机制,就...
本篇将深入探讨HashMap的线程安全问题,并提供相关的解决方案。 首先,我们需要了解HashMap在多线程环境下可能出现的问题: 1. **并发修改异常(ConcurrentModificationException)**:当多个线程同时修改HashMap...
本文将深入探讨在多线程环境中使用List时遇到的非线程安全问题,并提供相应的解决方案和最佳实践。 List是.NET框架中常用的一个动态数组,它提供了方便的增删改查操作。然而,List并未设计为线程安全的容器,这意味...
### Struts1、Struts2、WebWork框架中的线程安全问题分析 #### 一、Struts1与线程安全问题 在Struts1中,每个`Action`类实例是被多个请求重用的,这使得它在多线程环境下存在潜在的线程安全问题。当多个线程同时...
什么是线程安全? 答:线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等...
Java多线程-线程的安全问题与线程的同步机制介绍 在 Java 多线程编程中,线程安全问题是非常重要的一个话题。当多个线程访问同一个资源时,如果只有读操作那么不会出现线程安全问题,但是如果多个线程对资源进行读...
mysql是线程不安全的,mysql不是线程安全的,多线程共用同一个mysql连接是会崩溃的 QT的QSqlDatabase是基于mysql的,所以一样是线程不安全的 现讲明mysql为什么是线程不安全的,以及在多线程环境下如何使用mysql,...
在计算机编程领域,尤其是涉及到实时系统和并发编程时,线程锁和线程安全变量是至关重要的概念。LabWindows/CVI是一种流行的交互式C开发环境,特别适合于开发科学和工程应用。本实例将深入探讨如何在LabWindows/CVI...
SimpleDateFormat类的线程安全问题和解决方案 SimpleDateFormat类的线程安全问题 SimpleDateFormat类是Java提供的日期时间转化类,用于将日期和时间类型的数据进行解析和格式化。在Java开发中,SimpleDateFormat类...
在Java中,线程安全问题通常与并发、内存模型和可见性有关。Java内存模型(JMM)定义了如何在多线程环境下共享数据的规则,确保线程之间的正确交互。 线程安全可以分为三种类型: 1. 不安全:当多个线程访问共享...
### servlet与Struts action线程安全问题分析 #### 关键知识点概述 1. **Servlet的多线程机制**:Servlet的高效执行得益于其基于Java多线程机制的架构。Servlet容器在接收到客户端请求时,不会每次都创建新的...
线程安全的日志库在多线程环境下尤为重要,因为不正确的日志操作可能会导致数据竞争和同步问题。本文将详细讨论如何在C++中实现一个基于Win32接口的线程安全日志库,并关注其核心概念和技术。 首先,我们需要理解...
在IT行业中,尤其是在开发高并发应用时,线程安全是一个至关重要的问题。"C# 高效线程安全,解决多线程写txt日志类.zip" 提供了一个专门用于多线程环境下写入txt日志文件的解决方案,确保了在并发写入时的数据一致性...
描述中提到的源码测试可能包含以下内容:创建多个线程,每个线程执行一个包含局部变量的方法,然后观察结果以确定是否存在线程安全问题。测试可能包括对局部变量的读写操作,以及涉及到同步机制如synchronized关键字...
然而,如果不正确地处理线程安全问题,可能会导致程序运行异常甚至崩溃。 在上述的“Pro*C线程安全问题案例”中,问题出在一个名为`ProcHandle::Test`的函数上。这个函数用于删除名为`Test`的表中RULEID为`s_RuleID...