加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

java – 在测试中重现SimpleDateFormat非线程安全性

发布时间:2020-12-15 05:20:46 所属栏目:Java 来源:网络整理
导读:我有一个应用程序,它不时在日志中有这个堆栈跟踪: java.lang.ArrayIndexOutOfBoundsException: 514 at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:436) at java.util.GregorianCalendar.computeFields(GregorianCalen
我有一个应用程序,它不时在日志中有这个堆栈跟踪:

java.lang.ArrayIndexOutOfBoundsException: 514
        at sun.util.calendar.BaseCalendar.getCalendarDateFromFixedDate(BaseCalendar.java:436)
        at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:2081)
        at java.util.GregorianCalendar.computeFields(GregorianCalendar.java:1996)
        at java.util.Calendar.complete(Calendar.java:1312)
        at java.util.Calendar.get(Calendar.java:1093)
        at java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:917)
        at java.text.SimpleDateFormat.format(SimpleDateFormat.java:824)
        at java.text.SimpleDateFormat.format(SimpleDateFormat.java:796)
        at java.text.DateFormat.format(DateFormat.java:314)
        at me.myself.i.Message.toString(Message.java:203)
        at java.lang.String.valueOf(String.java:2615)
        at java.lang.StringBuilder.append(StringBuilder.java:116)

我认为这个问题可能存在于某些方面:

public class Message{
private transient DateFormat logDateFormat;
    @Override
    public String toString() {
        final StringBuilder result = new StringBuilder(getClass().getSimpleName());
        result.append("Time=").append(logDateFormat.format(new Date(getExpireTime())));     
        return result.toString();
    }
}

我认为多个线程同时调用toString(),但我在本地机器上重现这个问题:

@Before
  public void setUp() {
    message = new Message();
    pool = Executors.newFixedThreadPool(numOfThreads);
 }

  @Test
  public void multiThreadTest() {
        for (int i=0; i<numOfThreads; i++) {
            TestJob j = new TestJob(message);
            pool.submit(j);
        }
        pool.shutdown();
        while(!pool.isTerminated()){            
        }
    }

    class TestJob implements Runnable{

        private Message message;
        private int n=100;

        public TestJob(Message message) {
            this.message= message;
        }

        public void run() {
            for (int i=0; i<n; i++) {
                try{
                    System.out.println(message.toString());
                } catch(Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

如何编写正确的junit测试来重现此问题?

解决方法

由于我的第一次测试没有重现你的问题,试试这个

final SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
ExecutorService ex = Executors.newFixedThreadPool(1000);
for (;;) {
    ex.execute(new Runnable() {
        public void run() {
            try {
                f.format(new Date(new Random().nextLong()));
            } catch (Exception e) {
                e.printStackTrace();
                System.exit(1);
            }
        };
    });
}

这需要时间,但最后我得到了

java.lang.ArrayIndexOutOfBoundsException: 3144942
    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.complete(Calendar.java:1560)
    at java.util.Calendar.get(Calendar.java:1162)
    at java.text.SimpleDateFormat.subFormat(SimpleDateFormat.java:1093)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:978)
    at java.text.SimpleDateFormat.format(SimpleDateFormat.java:948)
    at java.text.DateFormat.format(DateFormat.java:336)
    at Test1$1.run(Test1.java:17)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1110)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:603)
    at java.lang.Thread.run(Thread.java:722)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读