Java – reproduce simpledateformat non thread safety in testing

I have an application that has this stack trace in the log from time to time:

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)

I think this problem may exist in some aspects:

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();
    }
}

I think multiple threads call tostring() at the same time, but I reproduce the problem on the local machine:

@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();
                }
            }
        }
    }

How do I write the correct JUnit test to reproduce this problem?

Solution

Since my first test didn't reproduce your problem, try this

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);
            }
        };
    });
}

It took time, but in the end I got it

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)
The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>