leisure

JAVA - exceed,helloworld
随笔 - 50, 文章 - 0, 评论 - 11, 引用 - 0
数据加载中……

SimpleDateFormat多线程并发下的不安全隐患

最近偶然发现一些数据的日期有错乱,而且时间出错格式无规律,有些去了1970年了,有些月份错了,有些号数变了,而日志上看并没有异常信息!

根据用户反应,常出现在某个批量更新操作中,于是乎,也按照用户描述的,线下操作了数遍,也没有出现这种情况。

有趣的是,就算在线上操作,也并不是一定会出现这种问题,只是偶然!

我开始怀疑底层代码问题了,因为那个操作,并没有修改到日期相关的字段,为了证实这点,经过我一番的排查,
问题终于定位在DateUtil.parse等方法上,parse方法调用了一个静态的simpleDateFormat.parse方法,为什么?!为什么这个方法不稳定的?
仔细阅读了java.util.SimpleDateFormat的api,发现此信息:

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.


很明显simpledateformat并不是线程同步的,以致并发的时候不安全!为了证实这点于是乎写了一个简单的测试程序。

package com.leisure;
import java.text.ParseException;
public class TestSimpleDateFormatThreadSafe extends Thread {
    @Override
    public void run() {
        while(true) {
            try {
                this.join(2000);
            } 
catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            try {
                System.out.println(DateUtil.parse(
"2011-10-11 06:02:20"));
            } 
catch (ParseException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        for(int i = 0; i < 20; i++)
            new TestSimpleDateFormatThreadSafe().start();
    }
}

package com.leisure;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateUtil {
    
private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    
public static Date parse(String str) throws ParseException {
        
return sdf.parse(str);
    }
}

输出结果:

Tue Oct 11 18:02:20 CST 2011

Tue Oct 11 18:02:20 CST 2011

Sun Oct 11 18:02:20 CST 1970

Tue Oct 11 18:02:20 CST 2011

Thu Jan 01 18:02:20 CST 1970

Sat Dec 11 18:02:20 CST 2010

Tue Oct 11 18:02:20 CST 2011

Exception in thread "Thread-18" java.lang.NumberFormatException: multiple points

at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

at java.lang.Double.parseDouble(Unknown Source)

at java.text.DigitList.getDouble(Unknown Source)

at java.text.DecimalFormat.parse(Unknown Source)

at java.text.SimpleDateFormat.subParse(Unknown Source)

at java.text.SimpleDateFormat.parse(Unknown Source)

at java.text.DateFormat.parse(Unknown Source)

at com.leisure.DateUtil.parse(DateUtil.java:12)

at com.leisure.TestSimpleDateFormatThreadSafe.run(TestSimpleDateFormatThreadSafe.java:16)

Fri Dec 23 19:02:20 CST 2011

Fri Dec 23 18:02:20 CST 2011

输出结果很明显了,跟线上数据出现的问题基本一致。不过按照这里看到的结果,有报错,再仔细阅读了应用的底层代码,
某个位置拦截了部份异常,没有记录也没有向上抛出处理,到这里,我只想问一句:底层代码谁写的?

posted on 2011-10-15 00:22 leisure 阅读(2862) 评论(0)  编辑  收藏 所属分类: java


只有注册用户登录后才能发表评论。


网站导航: