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

  • 相关阅读:
    SQL Server XML数据解析
    c# XML和实体类之间相互转换(序列化和反序列化)
    C#解析XML详解(XPath以及带命名空间NameSpace)
    Jquery实现按钮点击遮罩加载,处理完后恢复
    jquery控制div随滚动条滚动效果
    asp.net中利用Jquery+Ajax+Json实现无刷新分页(二)
    easyUI tree点击文字展开节点
    201805牛客模拟考
    策略模式
    非线程安全演变成线程安全---原子性与加锁机制
  • 原文地址:https://www.cnblogs.com/gisorange/p/3432020.html
Copyright © 2011-2022 走看看