zoukankan      html  css  js  c++  java
  • 关于jdk1.7的SimpleDateFormat类线程不安全

    项目中,经常会用到日期操作。今天在项目中,运行发现多线程调用SimpleDateFormat,抛出异常的情况,而且是选择性的抛出,实际环境很难复现。

         我们模拟以下2种场景:
      
    a、单实例场景1

    		final DateFormat df = new SimpleDateFormat("yyyyMMdd,HHmmss");
    		ExecutorService ts = Executors.newFixedThreadPool(100);
    		for (;;) {
    			ts.execute(new Runnable() {
    
    				@Override
    				public void run() {
    					try {
    						df.format(new Date(new Random().nextLong()));
    					} catch (Exception e) {
    						e.printStackTrace();
    						System.exit(1);
    					}
    				}
    			});
    		}
    

      

    b、多实例场景2

    	final ThreadLocal<DateFormat> tl = new ThreadLocal<DateFormat>(){
    			@Override
    			protected DateFormat initialValue() {
    				return new SimpleDateFormat("yyyyMMdd,HHmmss");
    			}
    			
    		};
    		ExecutorService ts = Executors.newFixedThreadPool(100);
    		for (;;) {
    			ts.execute(new Runnable() {
    
    				@Override
    				public void run() {
    					try {
    						tl.get().format(new Date(new Random().nextLong()));
    					} catch (Exception e) {
    						e.printStackTrace();
    						System.exit(1);
    					}
    				}
    			});
    		}
    

           运行结果对比可以看到,场景2可以稳定运行,而场景1却频率抛出如下异常:

    java.lang.ArrayIndexOutOfBoundsException: 2397709
        at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:454)
        at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2333)
        at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2248)
        at java.util.Calendar.setTimeInMillis(Calendar.java:1140)
        at java.util.Calendar.setTime(Calendar.java:1106)
        at java.text.SimpleDateFormat.format(SimpleDateFormat.java:955)
        at java.text.SimpleDateFormat.format(SimpleDateFormat.java:948)
        at java.text.DateFormat.format(DateFormat.java:336)
        at foo.Bar$1.run(Bar.java:24)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)

          看出 SimpleDateFormat.format并非线程安全的,建议可以采用以下方式解决:

    解决方法

    a、使用sychronized
    b、使用ThreadLocal
    c、每次使用new SimpleDateFormat实例
    d、也可以使用joda-time等第三方库

  • 相关阅读:
    2016.5.15——leetcode:Number of 1 Bits ,
    2016.5.14——leetcode-HappyNumber,House Robber
    记录学习过程
    npm 模块安装机制简介
    搭建Vue.js开发环境(window10)
    pwd 显示当前所在的工作路径
    Lucene 6.5.0 入门Demo
    java.lang.UnsupportedClassVersionError
    window.onload 和 $(document).ready(function(){}) 的区别
    plsql + 客户端 连接oracle数据库
  • 原文地址:https://www.cnblogs.com/gisorange/p/3432020.html
Copyright © 2011-2022 走看看