• JDK中的SimpleDateFormat线程非安全


      在JDK中使用SimpleDateFormat的时候都会遇到线程安全的问题,在JDK文档中也说明了该类是线程非安全的,建议对于每个线程都创建一个SimpleDateFormat对象。如下面一个Case中,多个线程去调用SimpleDateFormat中得parse方法:

    @Test
        public void testUnThreadSafe() throws Exception {
            final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
    
            final String[] dateStrings = {
                    "2014-04-30 18:51:01,61",
                    "2014-04-30 18:51:01,461",
                    "2014-04-30 18:51:01,361",
                    "2014-04-30 18:51:01,261",
                    "2014-04-30 18:51:01,161",
            };
            int threadNum = 5;
            Thread[] parseThreads = new Thread[threadNum];
            for (int i=0; i<threadNum; i++) {
               parseThreads[i] = new Thread(new Runnable() {
                   public void run() {
                       for (int j=0; j<dateStrings.length; j++) {
                           try {
                               System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
                           } catch (ParseException e) {
                               e.printStackTrace();
                           }
                       }
                   }
               });
               parseThreads[i].start();
            }
    
            for (int i=0; i<threadNum; i++) {
                parseThreads[i].join();
            }
        }

    将会抛出异常:java.lang.NumberFormatException: multiple points

    通常的解决办法有:

    1. 使用synchronized

    synchronized (sdf) {
      System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
    }

    2. 每用一次实例化一次

    try {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
        System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
    } catch (ParseException e) {
        e.printStackTrace();
    }

    3. 使用ThreadLocal

        @Test
        public void testUnThreadSafe() throws Exception {
    //        final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
            final ThreadLocal<SimpleDateFormat> localSdf = new ThreadLocal<SimpleDateFormat>();
            final String[] dateStrings = {
                    "2014-04-30 18:51:01,61",
                    "2014-04-30 18:51:01,461",
                    "2014-04-30 18:51:01,361",
                    "2014-04-30 18:51:01,261",
                    "2014-04-30 18:51:01,161",
            };
            int threadNum = 5;
            Thread[] parseThreads = new Thread[threadNum];
            for (int i=0; i<threadNum; i++) {
               parseThreads[i] = new Thread(new Runnable() {
                   public void run() {
                       for (int j=0; j<dateStrings.length; j++) {
                           try {
                               SimpleDateFormat sdf = localSdf.get();
                               if (sdf == null) {
                                   sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
                                   localSdf.set(sdf);
                               }
                               System.out.println(Thread.currentThread().getName() + " " + sdf.parse(dateStrings[j]));
                           } catch (ParseException e) {
                               e.printStackTrace();
                           }
                       }
                   }
               });
               parseThreads[i].start();
            }
    
            for (int i=0; i<threadNum; i++) {
                parseThreads[i].join();
            }
        }

    第一种和第二种解决方案对于一个工具类来说都会带来昂贵的资源开销,建议使用ThreadLocal创建一个对单个线程来说全局的变量,保证线程安全,当然可以使用第三方工具类如Apache commons 里的FastDateFormat或者Joda-Time类库来处理。

  • 相关阅读:
    使用AD你应该避免的五个错误
    卸载常用组件
    学会批处理,用心学很容易
    VI的用法
    安装Linux版VNC 企业版
    【3】淘宝sdk的下载和安装
    【7】创建一个自己的模板
    【6】网店模板目录及文件介绍
    【11】淘宝sdk的DOM、CSS规范、Widget规范(这个Widget规范差不多就是网页效果)和HTML规范
    【2】认识淘宝sdk模板
  • 原文地址:https://www.cnblogs.com/nexiyi/p/SimpleDateFormat_ThreadSafe_Solution.html
Copyright © 2020-2023  润新知