• 多线程避免使用SimpleDateFormat及替代方案


    先来看一个多线程下使用例子,看到运行结果会出现异常:

    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Random;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
     
    public class SimpleDateFormateTest {
     
        public static void main(String[] args) {
            final DateFormat df = new SimpleDateFormat("yyyyMMdd,HHmmss");
            ExecutorService ts = Executors.newFixedThreadPool(100);
            for (;;) {
                ts.execute(new Runnable() {         
                    @Override
                    public void run() {
                        try {
                          //生成随机数,格式化日期
                          String format =  df.format(new Date(Math.abs(new Random().nextLong())));
                          System.out.println(format);
                        } catch (Exception e) {
                            e.printStackTrace();
                            System.exit(1);
                        }
                    }
                });
            }
        }    
    }

    运行结果:

     

    在并发环境下使用SimpleDateFormat,正常的打开放式如下:

    为了能够在多线程环境下使用SimpleDateFormat,有这六种方法:

    方法一

    在需要执行格式化的地方都新建SimpleDateFormat实例,使用局部变量来存放SimpleDateFormat实例

    public static  String formatDate(Date date)throws ParseException{
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
      return sdf.format(date);
    }

    这种方法可能会导致短期内创建大量的SimpleDateFormat实例,如解析一个excel表格里的字符串日期。

    方法二

    为了避免创建大量的SimpleDateFormat实例,往往会考虑把SimpleDateFormat实例设为静态成员变量,共享SimpleDateFormat对象。这种情况下就得对SimpleDateFormat添加同步。

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    
    public static String formatDate(Date date)throws ParseException{
      synchronized(sdf){
        return sdf.format(date);
      }  
    }

    这种方法的缺点也很明显,就是在高并发的环境下会导致解析被阻塞。

    方法三 

    方法加同步锁synchronized,在同一时刻,只有一个线程可以执行类中的某个方法。

    缺点:性能较差,每次都要等待锁释放后其他线程才能进入。

    方案四 使用第三方包

    这个我有尝试cn.hutoolcommon-lang3提供的FastDateFormat 
    最后的结果其实并不满意,因为这两个包都没能帮助我检查非正常时间,比如2018-07-32这种日期也被认为是正确的时期格式了

    方法五(推荐

    要在高并发环境下能有比较好的体验,可以使用ThreadLocal来限制SimpleDateFormat只能在线程内共享,这样就避免了多线程导致的线程安全问题。

     private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() {
        @Override
        protected DateFormat initialValue() {
            return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
    };
    
    public static String format(Date date) {
        return threadLocal.get().format(date);
    }

    方案六 DateTimeFormatter使用

    Java8提供了新的日期时间API,其中包括用于日期时间格式化的DateTimeFormatter,它与SimpleDateFormat的有什么区别呢?

    问题解决

    两者最大的区别是,Java8的DateTimeFormatter也是线程安全的,而SimpleDateFormat并不是线程安全。

    解析日期

    String dateStr= "2016年10月25日"; 
    DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");   
    LocalDate date= LocalDate.parse(dateStr, formatter); 
    

    日期转换为字符串

    LocalDateTime now = LocalDateTime.now();  
    DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy年MM月dd日 hh:mm a"); 
    String nowStr = now .format(format);

    由DateTimeFormatter的静态方法ofPattern()构建日期格式,LocalDateTime和LocalDate等一些表示日期或时间的类使用parse和format方法把日期和字符串做转换。

    使用新的API,整个转换过程都不需要考虑线程安全的问题。

  • 相关阅读:
    使用 JDBC 驱动程序
    (转载)SQL Server 2008 连接JDBC详细图文教程
    (转载)VB中ByVal与ByRef的区别
    (转载)Java里新建数组及ArrayList java不允许泛型数组
    在VS2008环境下编写C语言DLL,并在C++和C#项目下调用 (转载)
    近期计划
    在服务器上使用python-gym出现的关于显示的问题
    字符串匹配
    Ubuntu18.04 桌面系统的个人吐槽(主要是终端)
    Ubuntu18.04上安装N卡驱动、CUDA、CUDNN三连
  • 原文地址:https://www.cnblogs.com/barrywxx/p/11426807.html
Copyright © 2020-2023  润新知