• SimpleDateFormat做成员或者静态成员多线程安全隐患


    转自:http://blog.csdn.net/jeamking/article/details/7183958

    有时我们在同一个类中都是使用同一种日期格式,又或者为了减少new SimpleDateFormat次数,自然而然的就会出现如下代码:

    private static SimpleDateFormat sdf = newSimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    但是这样做在多线程并发下会存在安全隐患。SimpleDateFormat 类并不是线程同步的,JDK中我们可以看到如下描述:

    * Date formats are not synchronized.

     * Itis recommended to create separate format instances for each thread.

     * Ifmultiple threads access a format concurrently, it must be synchronized

     *externally.

    下面通过一个简单程序来进行测试:

    public class DateUtil {

           privatestatic SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");

           publicDate parse(String str) throws ParseException{

                  returnsdf.parse(str);

           }

    }

    public class Test {

           /**

            * @param args

            * @throws InterruptedException

            */

           publicstatic void main(String[] args) throws InterruptedException {

                  SdfRunnablett = new SdfRunnable();

                  for(inti=0;i<10;i++){

                         newThread(tt).start();

                  }

           }

    }

    输出结果:

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

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

           atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

           atjava.lang.Double.parseDouble(Unknown Source)

           atjava.text.DigitList.getDouble(Unknown Source)

           atjava.text.DecimalFormat.parse(Unknown Source)

           atjava.text.SimpleDateFormat.subParse(Unknown Source)

           atjava.text.SimpleDateFormat.parse(Unknown Source)

           atjava.text.DateFormat.parse(Unknown Source)

           atDateUtil.parse(DateUtil.java:8)

           atSdfRunnable.run(SdfRunnable.java:8)

           atjava.lang.Thread.run(Unknown Source)

    多运行几次,并不每次都输出这个错误信息,还可能输出如下错误信息:

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Wed Sep 23 12:23:35 CST 2201

    Fri Dec 23 12:23:35 CST 2011

    Exception in thread "Thread-6"java.lang.NumberFormatException: empty String

           atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

           atjava.lang.Double.parseDouble(Unknown Source)

           atjava.text.DigitList.getDouble(Unknown Source)

           atjava.text.DecimalFormat.parse(Unknown Source)

           atjava.text.SimpleDateFormat.subParse(Unknown Source)

           atjava.text.SimpleDateFormat.parse(Unknown Source)

           atjava.text.DateFormat.parse(Unknown Source)

           atDateUtil.parse(DateUtil.java:8)

           atSdfRunnable.run(SdfRunnable.java:8)

           atjava.lang.Thread.run(Unknown Source)

    Exception in thread "Thread-1"java.lang.NumberFormatException: For input string: ""

           atjava.lang.NumberFormatException.forInputString(Unknown Source)

           atjava.lang.Long.parseLong(Unknown Source)

           atjava.lang.Long.parseLong(Unknown Source)

           atjava.text.DigitList.getLong(Unknown Source)

           atjava.text.DecimalFormat.parse(Unknown Source)

           atjava.text.SimpleDateFormat.subParse(Unknown Source)

           atjava.text.SimpleDateFormat.parse(Unknown Source)Fri Dec 23 12:23:35 CST 2011

           atjava.text.DateFormat.parse(Unknown Source)

           atDateUtil.parse(DateUtil.java:8)

           atSdfRunnable.run(SdfRunnable.java:8)

           atjava.lang.Thread.run(Unknown Source)

    在以上示例中我们把SimpleDateFormat定义为静态成员的。接下来我们把SimpleDateFormat定义为类普通成员。

    public class DateUtil {

           privateSimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

           publicDate parse(String str) throws ParseException{

                  returnsdf.parse(str);

           }

    }

    再次运行程序,结果如下:

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    Fri Dec 23 12:23:35 CST 2011

    程序运行正常。并没有出现错误信息。那么,是不是意味着SimpleDateFormat作为普通成员就没有安全隐患呢,请看如下示例:

    public class SdfRunnable implementsRunnable {

           privateSimpleDateFormat sdf;

           privateString dateStr;

           publicSdfRunnable(SimpleDateFormat sdf,String dateStr){

                  this.sdf= sdf;

                  this.dateStr= dateStr;

           }

           publicvoid run() {

                  try{

                         System.out.println(this.sdf.parseObject(this.dateStr));

                  }catch (ParseException e) {

                         e.printStackTrace();

                  }

           }

    }

    public class Test {

           /**

            * @param args

            * @throws InterruptedException

            */

           publicstatic void main(String[] args) throws InterruptedException {

                  SimpleDateFormatsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

                  SdfRunnablett = new SdfRunnable(sdf,"2011-12-34 12:23:11");

                  for(inti=0;i<10;i++){

                         newThread(tt).start();

                  }

           }

    }

    运行输出结果如下:

    Tue Jan 03 12:23:11 CST 2012

    Tue Jan 03 12:23:11 CST 2012

    Tue Jan 03 12:23:11 CST 2012

    Tue Jan 03 12:23:11 CST 2012

    Tue Jan 03 12:23:11 CST 2012

    Thu Jan 01 00:00:11 CST 1970

    Sun Jan 03 12:23:11 CST 1971

    Tue Jan 03 12:23:11 CST 2012

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

           atsun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)

           atjava.lang.Double.parseDouble(Unknown Source)

           atjava.text.DigitList.getDouble(Unknown Source)

           atjava.text.DecimalFormat.parse(Unknown Source)

           atjava.text.SimpleDateFormat.subParse(Unknown Source)

           atjava.text.SimpleDateFormat.parse(Unknown Source)

           atjava.text.DateFormat.parseObject(Unknown Source)

           atjava.text.Format.parseObject(Unknown Source)

           atSdfRunnable.run(SdfRunnable.java:14)

           atjava.lang.Thread.run(Unknown Source)

    由此可见,不管是SimpleDateFormat作为静态成员还是成员,在多线程并发下都会存在安全隐患。所以应该在需要使用的地方再new SimpleDateFormat()。

    关于SimpleDateFormat非多线程安全问题,在sun的bug database(http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4228335)中有更多的描述。

  • 相关阅读:
    Shodan新手入坑指南
    linux 下查看网卡工作速率
    centos关闭ipv6
    springBoot----@ConditionalOnxxx相关注解总结
    ElasticSearch Root身份运行
    CentOS6 Install kafka
    CentOS 7 中firewall-cmd命令
    sensu
    metrics+spring+influxdb
    SpringBoot(十二):SpringBoot整合Kafka
  • 原文地址:https://www.cnblogs.com/xiyuanbaiyun/p/3376139.html
Copyright © 2020-2023  润新知