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

  • 相关阅读:
    PAT1037:Magic Coupon
    PAT1081:Rational Sum
    PAT1039: Course List for Student
    PAT1069:The Black Hole of Numbers
    VC++中字符串编码处理的一些相关问题
    PAT1110:Complete Binary Tree
    Java编译器003---javac -d/-sourcepath/-classpath选项
    Java编译器002---javac -source/-target选项
    Java编译器001---javac -g选项
    力扣练习010---把字符串转换成整数
  • 原文地址:https://www.cnblogs.com/gisorange/p/3432020.html
Copyright © 2020-2023  润新知