SimpleDateFormat 类性能问题

    xiaoxiao2021-12-04  16

    SimpleDateFormat类

    1.首先了解包结构

    java.text.SimpleDateFormat

          -- -java.text.DateFormat

             ----java.text.Format

                ---java.lang.Object

    2.常用的方法

      2.1 date (java.util.Date)转 string

     

           SimpleDateFormatdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");

    String  str=df.format(new Date());

     

    2.2 string 转 date

     

    SimpleDateFormat df = newSimpleDateFormat("yyyyMMddHHmmssSSS");

    Date date=df. parse (“20140201120202111”);

     

    3.线程不安全

      原因:

    SimpleDateFormat(下面简称sdf)类内部有一个Calendar对象引用,它用来储存和这个sdf相关的日期信息,例如sdf.parse(dateStr),sdf.format(date)诸如此类的方法参数传入的日期相关String, Date等等,都是交友Calendar引用来储存的.这样就会导致一个问题,如果你的sdf是个static,那么多个thread之间就会共享这个sdf,同时也是共享这个Calendar引用,并且,观察 sdf.parse()方法,你会发现有如下的调用:

    DataFormat类中Parse方法调用了一个抽象方法,这里就巧妙的实现了入口统一在父类中,具体使用的方法在子类中实现。

     

     

     

    SimpleDateFormat类中具体实现了父类的抽象方法

     

     

    这个方法中最重要的代码注意我选中的方法

     

    我选中的方法具体代码如下

    java.text .CalendarBuilder类路径

     

     

    这里会导致的问题就是,如果线程A调用了 sdf.parse(),并且进行了 calendar.clear()后还未执行calendar.getTime()的时候,线程B又调用了sdf.parse(),这时候线程B也执行了sdf.clear()方法,这样就导致线程A的的calendar数据被清空了(实际上A,B的同时被清空了).又或者当 A执行了calendar.clear()后被挂起,这时候B开始调用sdf.parse()并顺利i结束,这样 A calendar内存储的的date变成了后来B设置的calendardate

     

     

     

    4.解决方案

     

    import java.text.ParseException;

    import java.text.SimpleDateFormat;

    import java.util.Date;

    import java.util.HashMap;

    import java.util.Map;

     

    /**

     * @author zhenwei.liu created on 2013 13-8-29 下午5:35

     * @version $Id$

     */

    public class DateUtil {

     

       /** 锁对象 */

       private static final Object lockObj = new Object();

     

       /** 存放不同的日期模板格式的sdf的Map */

       private static Map<String, ThreadLocal<SimpleDateFormat>>sdfMap = new HashMap<String, ThreadLocal<SimpleDateFormat>>();

     

       /**

         * 返回一个ThreadLocal的sdf,每个线程只会new一次sdf

         *

         * @param pattern

         * @return

         */

       private static SimpleDateFormat getSdf(final String pattern) {

            ThreadLocal<SimpleDateFormat> tl= sdfMap.get(pattern);

     

            // 此处的双重判断和同步是为了防止sdfMap这个单例被多次put重复的sdf

            if (tl == null) {

                synchronized (lockObj) {

                    tl = sdfMap.get(pattern);

                    if (tl == null) {

                        // 只有Map中还没有这个pattern的sdf才会生成新的sdf并放入map

                       System.out.println("put new sdf of pattern " + pattern +" to map");

     

                        // 这里是关键,使用ThreadLocal<SimpleDateFormat>替代原来直接new SimpleDateFormat

                        tl = newThreadLocal<SimpleDateFormat>() {

     

                            @Override

                            protectedSimpleDateFormat initialValue() {

                               System.out.println("thread: " + Thread.currentThread() +" init pattern: " + pattern);

                                return newSimpleDateFormat(pattern);

                            }

                        };

                        sdfMap.put(pattern, tl);

                    }

                }

            }

     

            return tl.get();

       }

     

       /**

         * 是用ThreadLocal<SimpleDateFormat>来获取SimpleDateFormat,这样每个线程只会有一个SimpleDateFormat

         *

         * @param date

         * @param pattern

         * @return

         */

       public static String format(Date date, String pattern) {

            return getSdf(pattern).format(date);

       }

     

       public static Date parse(String dateStr, String pattern) throwsParseException {

            return getSdf(pattern).parse(dateStr);

       }

     

    }

    转载请注明原文地址: https://ju.6miu.com/read-680246.html

    最新回复(0)