线程安全之SimpleDateFormat

线程安全,作何解?

多线程环境中,当涉及到共享数据时候,就要考虑线程安全问题。要进行同步,就是加锁,关键字synchronized 。就是同一时刻只能有一个线程访问共享资源。

举例说明,引用来自

http://www.importnew.com/23010.html?replytocom=539047#respond

高并发情况下,使用工具类

public class DateUtil {

    private DateUtil(){}

    private static final DateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    public static Date parse(String date)  throws ParseException {
        return DATE_FORMAT.parse(date);
    }    

由此而造成异常

java.lang.NumberFormatException: For input string: ""
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
        at java.lang.Long.parseLong(Long.java:431)
        at java.lang.Long.parseLong(Long.java:468)
        at java.text.DigitList.getLong(DigitList.java:177)
        at java.text.DecimalFormat.parse(DecimalFormat.java:1297)
        at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1589)
        at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1311)
        at java.text.DateFormat.parse(DateFormat.java:335)
        at com.xxxxxxx.core.common.util.DateUtil.parseTimestamp(DateUtil.java:95)
        at com.xxxxxxx.core.common.util.DateUtil.parse(DateUtil.java:84)
        at com.xxxxxxx.hbase.generator.LogRowKeyGenerator.generate(LogRowKeyGenerator.java:21)
        ... 22 more
那么为什么出现这个问题??

查看SimpleDateFormat的源码会发现,最前面的注释

* 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.

翻译过来就是

日期格式化的类是非同步的,建议为每一个线程创建独立的格式化实例。如果多个线程并发访问同一个格式化实例,就必须在外部添加同步机制

说明这样做是线程不安全的(把DateFormat DATE_FORMAT = new SimpleDateFormat(“yyyy-MM-dd HH:mm:ss”) 作为了全局变量,是一个共享资源)。

所以正确做法是

public class DateUtil {

    private DateUtil(){}

    public static Date parse(String date)  throws ParseException {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(date);
    }    

}

总结

把一个非同步 *Date formats are not synchronized的作为全局变量,也就是一个共享资源,没有加上锁,在高并发的情况下,出现意想不到的bug。现在的改法是把其变成非共享的资源,也就是为每一个线程创建独立的格式化实例,这样就不用使用锁来解决了。

提示

  1. 时间相关的操作建议使用Java 8新添加的Time包

  2. 共享对象时, 基本都会去看看类是不是线程安全的。谷歌guava库, joda-time, jackson这些常用的工具包, 在类的注释上都会标明是不是thread safe

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值