zoukankan      html  css  js  c++  java
  • SimpleDateFormat线程不安全(转)

     有三种方法可以解决以上安全问题。
      1).使用同步

     1 package com.bijian.study.date;
     2 
     3 import java.text.ParseException;
     4 import java.text.SimpleDateFormat;
     5 import java.util.Date;
     6 
     7 public class DateUtil02 implements DateUtilInterface {
     8 
     9     private SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    10     
    11     @Override
    12     public void format(Date date) {
    13         System.out.println(dateformat.format(date));
    14     }
    15 
    16     @Override
    17     public void parse(String str) {
    18         try {
    19             synchronized(dateformat){
    20                 System.out.println(dateformat.parse(str));
    21             }
    22         } catch (ParseException e) {
    23             e.printStackTrace();
    24         }
    25     }
    26 }


    修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil01();为DateUtilInterface dateUtil = new DateUtil02();测试OK。

            不过,当线程较多时,当一个线程调用该方法时,其他想要调用此方法的线程就要block,这样的操作也会一定程度上影响性能。

      2).每次使用时,都创建一个新的SimpleDateFormat实例

     1 package com.bijian.study.date;
     2 
     3 import java.text.ParseException;
     4 import java.text.SimpleDateFormat;
     5 import java.util.Date;
     6 
     7 public class DateUtil03 implements DateUtilInterface {
     8 
     9     @Override
    10     public void format(Date date) {
    11         
    12         SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    13         System.out.println(dateformat.format(date));
    14     }
    15 
    16     @Override
    17     public void parse(String str) {
    18         try {
    19             SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    20             System.out.println(dateformat.parse(str));
    21         } catch (ParseException e) {
    22             e.printStackTrace();
    23         }
    24     }
    25 }

    修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil02();为DateUtilInterface dateUtil = new DateUtil03();测试OK。

      

      3).借助ThreadLocal对象每个线程只创建一个实例

         借助ThreadLocal对象每个线程只创建一个实例,这是推荐的方法

         对于每个线程SimpleDateFormat不存在影响他们之间协作的状态,为每个线程创建一个SimpleDateFormat变量的拷贝或者叫做副本,代码如下:

     1 package com.bijian.study.date;
     2 
     3 import java.text.DateFormat;
     4 import java.text.ParseException;
     5 import java.text.SimpleDateFormat;
     6 import java.util.Date;
     7 
     8 public class DateUtil04 implements DateUtilInterface {
     9 
    10     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    11 
    12     // 第一次调用get将返回null
    13     private static ThreadLocal threadLocal = new ThreadLocal(){
    14         protected Object initialValue() {  
    15             return null;//直接返回null  
    16         } 
    17     };
    18     
    19     // 获取线程的变量副本,如果不覆盖initialValue,第一次get返回null,故需要初始化一个SimpleDateFormat,并set到threadLocal中
    20     public static DateFormat getDateFormat() {
    21         DateFormat df = (DateFormat) threadLocal.get();
    22         if (df == null) {
    23             df = new SimpleDateFormat(DATE_FORMAT);
    24             threadLocal.set(df);
    25         }
    26         return df;
    27     }
    28 
    29     @Override
    30     public void parse(String textDate) {
    31 
    32         try {
    33             System.out.println(getDateFormat().parse(textDate));
    34         } catch (ParseException e) {
    35             e.printStackTrace();
    36         }
    37     }
    38 
    39     @Override
    40     public void format(Date date) {
    41         System.out.println(getDateFormat().format(date));
    42     }
    43 }

    创建一个ThreadLocal类变量,这里创建时用了一个匿名类,覆盖了initialValue方法,主要作用是创建时初始化实例。

             也可以采用下面方式创建。

     1 package com.bijian.study.date;
     2 
     3 import java.text.DateFormat;
     4 import java.text.ParseException;
     5 import java.text.SimpleDateFormat;
     6 import java.util.Date;
     7 
     8 public class DateUtil05 implements DateUtilInterface {
     9 
    10     private static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
    11     
    12     @SuppressWarnings("rawtypes")
    13     private static ThreadLocal threadLocal = new ThreadLocal() {
    14         protected synchronized Object initialValue() {
    15             return new SimpleDateFormat(DATE_FORMAT);
    16         }
    17     };
    18 
    19     public DateFormat getDateFormat() {
    20         return (DateFormat) threadLocal.get();
    21     }
    22 
    23     @Override
    24     public void parse(String textDate) {
    25 
    26         try {
    27             System.out.println(getDateFormat().parse(textDate));
    28         } catch (ParseException e) {
    29             e.printStackTrace();
    30         }
    31     }
    32 
    33     @Override
    34     public void format(Date date) {
    35         System.out.println(getDateFormat().format(date));
    36     }
    37 }

    修改DateMainTest.java的DateUtilInterface dateUtil = new DateUtil03();为DateUtilInterface dateUtil = new DateUtil04();或者DateUtilInterface dateUtil = new DateUtil05();测试OK。

          最后,当然也可以使用apache commons-lang包的DateFormatUtils或者FastDateFormat实现,apache保证是线程安全的,并且更高效。

         附:Oracle官方bug说明: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6178997

      转自 http://bijian1013.iteye.com/blog/1873336

  • 相关阅读:
    excel 2003系列
    DataTab转换XML XML转换DataTable 的类[转]
    全角转半角与半角转全角
    Day2
    Day6 && Day7图论
    Day1
    Android为何以及如何保存Fragment实例
    Android应用的本地化及知识拓展之配置修饰符
    Leetcode NO.136 Single Number 只出现一次的数字
    经典排序算法(四) —— Quick Sort 快速排序
  • 原文地址:https://www.cnblogs.com/SamuelSun/p/4064256.html
Copyright © 2011-2022 走看看