another is: java thread safe regarding SimpleDateFormat

We have an OMS component using camel listen and poll MQ. To enhance the performance, I increased the thread listening to the queue, from


    from(""GShareMQ:queue:Q.US_OE.IN.TRANSACTIONSCHEDULE?acknowledgementModeName=CLIENT_ACKNOWLEDGE")
        // keep the JMS message for Client acknowledge on success
        .beanRef("jmsMessageUtil", "addMessageToHeader")
        .convertBodyTo(String.class)
        .log(LoggingLevel.INFO, "Processing SSB Execution:\n${in.body}")

        .beanRef("transactionScheduleParser", "parseTransactionScheduleMessage")

to

 from(""GShareMQ:queue:Q.US_OE.IN.TRANSACTIONSCHEDULE?acknowledgementModeName=CLIENT_ACKNOWLEDGE&concurrentConsumers=10")
        // keep the JMS message for Client acknowledge on success
        .beanRef("jmsMessageUtil", "addMessageToHeader")
        .convertBodyTo(String.class)
        .log(LoggingLevel.INFO, "Processing SSB Execution:\n${in.body}")

        .beanRef("transactionScheduleParser", "parseTransactionScheduleMessage")

then on off, out of few thousand messages, 20 got some exception as


java.lang.NumberFormatException: multiple points
	at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1084)
	at java.lang.Double.parseDouble(Double.java:510)
	at java.text.DigitList.getDouble(DigitList.java:151)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1303)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1936)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312)
	at java.text.DateFormat.parse(DateFormat.java:335)
	at com.bfm.cpm.parser.TransactionScheduleParser.parseTransactionScheduleMessage(TransactionScheduleParser.java:145)

or

java.lang.NumberFormatException: For input string: ""
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
	at java.lang.Long.parseLong(Long.java:431)
	at java.lang.Long.parseLong(Long.java:468)
	at java.text.DigitList.getLong(DigitList.java:177)
	at java.text.DecimalFormat.parse(DecimalFormat.java:1298)
	at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1591)
	at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1312)
	at java.text.DateFormat.parse(DateFormat.java:335)
	at com.bfm.cpm.parser.TransactionScheduleParser.parseTransactionScheduleMessage(TransactionScheduleParser.java:137)

line 137 and 145 are

        Date prvDt = prvDateFmt.parse(prvDateStr);
Date contrSettlementdate = prvDateFmt.parse(contrSettlementdateStr);

and prvDateFmt is instance variable, which is not thread safe.
http://stackoverflow.com/questions/6840803/simpledateformat-thread-safety

private SimpleDateFormat prvDateFmt = new SimpleDateFormat("yyyy-MM-dd");

When cpm parsing the message, it uses transactionScheduleParserBean as a singleton (Spring), which uses one same instance of SimpleDateFormat, and it is not threadSafe.

Date prvDt = prvDateFmt.parse(prvDateStr);
Date contrSettlementdate = prvDateFmt.parse(contrSettlementdateStr);

============================================updated on Aug 15, 2012
Solution:

I am to using the ThreadLocal class, which would provide one instance per thread.Think this should work.

here instead of using instance of SimpleDateFormat, I am to use instance of ThreadLocal as instance variable of the singleton spring bean, TransactionScheduleParser.

  private ThreadLocal<SimpleDateFormat> postingDateFmt = new ThreadLocal<SimpleDateFormat>(){
	
	  @Override
	protected SimpleDateFormat initialValue() {
		// TODO Auto-generated method stub
	       SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-ddHH:mm:ss");
		   df.setTimeZone(omsTz);
		   return df;
	}
  };
  
  private ThreadLocal<SimpleDateFormat> prvDateFmt = new ThreadLocal<SimpleDateFormat>(){
		
	  @Override
	protected SimpleDateFormat initialValue() {
		// TODO Auto-generated method stub
       SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
	   df.setTimeZone(omsTz);
	   return df;
	}
  };

while within the method, which is per thread level, instead of using the instance variable of type SimpleDateFormat, I am to use instance variable of type ThreadLocal to get one SimpleDateFormat per thread.

Date contrSettlementdate = prvDateFmt.get().parse(contrSettlementdateStr);
Date actualSettlementdate = prvDateFmt.get().parse(actualSettlementdateStr);

Addon: How ThreadLocal works:
Basically, each instance of type ThreadLocal would maintain one hashMap of Thread(threadId?) and the instance of ClassType. Invoking prvDateFmt.get() would return the instance of SimpleDateFormat corresponding to this thread.

Advertisements

Author: lwpro2

Java J2EE professional

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s