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

  • 相关阅读:
    从零开始入门 K8s | 应用编排与管理
    209. Minimum Size Subarray Sum
    208. Implement Trie (Prefix Tree)
    207. Course Schedule
    203. Remove Linked List Elements
    183. Customers Who Never Order
    182. Duplicate Emails
    181. Employees Earning More Than Their Managers
    1261. Find Elements in a Contaminated Binary Tree
    1260. Shift 2D Grid
  • 原文地址:https://www.cnblogs.com/SamuelSun/p/4064256.html
Copyright © 2011-2022 走看看