记一次SimpleDateFormat出现的线程安全问题

    以前只把SimpleDateFormat类当前一个简单的工具类使用,并没有注意它存在的线程安全问题,直到最近在近期一个数据迁移项目中才碰到。我的迁移程序会比较迁移前和后的数据是否一致,在做这个事情的时候,由于之前的数据库中存储的日期使用的14位字符串,即20140502112230,而新库中规范要求使用Timestamp类型,这自然要涉及到日期类型与字符串之间的转化。因为日期格式固定,因此我将这个方法封装在了一个工具类中,并将SimpleDateFormat类的变量声明成了一个类变量,如下:

public class Util {
    // 声明了一个静态变量
    static final SimpleDateFormat yyyyMMddHHmmss = new SimpleDateFormat("yyyyMMddHHmmss");

    public static Timestamp str2TimeStamp(String datestr) {
        try {
            if (StringUtils.isBlank(datestr) || datestr.length() != 14) {
                return null;
            }
            Date d = yyyyMMddHHmmss.parse(datestr);
            return new Timestamp(d.getTime());
        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }

    public static String timeStamp2String(Timestamp t) {
        if (t == null) {
            return null;
        }
        return yyyyMMddHHmmss.format(t);
    }
}

   在执行多线程的比较程序过程中,发现日期值老是错误,断点查看,明明字符串是20140502112230,Timestamp却出现了另外的值,才意识到SimpleDateFormat的线程安全问题,赶紧查看javadoc:

Synchronization

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.

   意思是说,该日期格式类不是同步的。所以建议在使用的时候,为每个线程单独创建一个SimpleDateForm实例。如果非要多个线程并发地访问一个实例,那么必须使用额外的同步。

    或者我们可以把相应的对象放到ThreadLocal中,多个线程调用时使用的都是各自线程中的副本,就不会出现线程安全问题了。

public static final ThreadLocal<SimpleDateFormat> sdfThread = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值