多线程下调用SimpleDateFormat的问题

来源:互联网 发布:mac无法连接localhost 编辑:程序博客网 时间:2024/06/05 10:35

SimpleDateFormat类用于时间格式的处理:

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd", Locale.CHINA);// 输出北京时间String currentNetworkTime = "2017-09-19";Date date_from_network = Constants.sdf.parse(currentNetworkTime);

结果:

date_from_network:Tue Sep 19 00:00:00 GMT+08:00 2017

parse可以将简单的时间字符串转换成标准的时间格式,然而

SimpleDateFormat不是线程安全的

做了这样一个测试,固定输入,开启100个线程进行时间格式转换:

            for (int i = 0 ;i<100;i++){                    Thread thread = new Thread(new Runnable() {                        @Override                        public void run() {                            String currentNetworkTime = "2017-09-19";                            try {                                Log.i(CLASS_TAG, "currentNetworkTime:" + currentNetworkTime);                                Date date_from_network = Constants.sdf.parse(currentNetworkTime);                                Log.i(CLASS_TAG, "date_from_network:" + date_from_network);                            } catch (ParseException e) {                                e.printStackTrace();                            }                        }                    });                    thread.start();                }

然后其中一些线程会出现异常:

09-19 10:35:36.889 26529 27665 I ecm_ecms: ->EcmServiceManager:currentNetworkTime:2017-09-1909-19 10:35:36.890 26529 27665 I ecm_ecms: ->EcmServiceManager:date_from_network:09-19 10:35:36.890 26529 27665 I ecm_ecms: ->EcmServiceManager: date_from_network:Fri Sep 11 00:00:00 GMT+08:00 2201

第一次打印结果居然是空的,第二次打印结果居然是2201年!
当然最好的改法是把SimpleDateFormat重新做一次封装,然后替换:

import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;public class DateSyncUtil {    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");    public static String format(Date date)throws ParseException{        synchronized(sdf){            return sdf.format(date);        }      }    public static Date parse(String strDate) throws ParseException{        synchronized(sdf){            return sdf.parse(strDate);        }    } }

后记:
一开始从日志里根本看不出什么问题,用日志里面的数据重新测试也无法复现,后来发现这部分代码在相同时间内调用了两次才怀疑是多线程并发引起的,然后从上层模拟多线程调用,发现当线程数量增大后结果竟然有一定随机性,增加打印,进一步缩小范围最后才定位到是SimpleDateFormat原因。