• 关于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等第三方库

  • 相关阅读:
    CF1172F
    CF506E
    【清华集训2014】玛里苟斯
    CF516E Drazil and His Happy Friends
    [NOI2017]游戏(2-SAT)
    [bzoj2878][Noi2012]迷失游乐园(基环树dp)
    bzoj3545/bzoj3551 [ONTAK2010]Peaks/Peaks加强版
    [bzoj1791][ioi2008]Island 岛屿(基环树、树的直径)
    [AT2306]Rearranging(拓扑序)
    [bzoj5301][Cqoi2018]异或序列
  • 原文地址:https://www.cnblogs.com/gisorange/p/3432020.html
Copyright © 2020-2023  润新知