Friday, 10 May 2019

multithreading - "Java DateFormat is not threadsafe" what does this leads to?



Everybody cautions regarding Java DateFormat not being thread safe and I understand the concept theoretically.




But I'm not able to visualize what actual issues we can face due to this. Say, I've a DateFormat field in a class and the same is used in different methods in the class (formatting dates) in a multi-threaded environment.



Will this cause:




  • any exception like format exception

  • discrepancy in data

  • any other issue?




Also, please explain why.


Answer



Let's try it out.



Here is a program in which multiple threads use a shared SimpleDateFormat.



Program:



public static void main(String[] args) throws Exception {


final DateFormat format = new SimpleDateFormat("yyyyMMdd");

Callable task = new Callable(){
public Date call() throws Exception {
return format.parse("20101022");
}
};

//pool with 5 threads
ExecutorService exec = Executors.newFixedThreadPool(5);

List> results = new ArrayList>();

//perform 10 date conversions
for(int i = 0 ; i < 10 ; i++){
results.add(exec.submit(task));
}
exec.shutdown();

//look at the results
for(Future result : results){

System.out.println(result.get());
}
}


Run this a few times and you will see:



Exceptions:



Here are a few examples:




1.



Caused by: 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:1589)



2.



Caused by: java.lang.NumberFormatException: For input string: ".10201E.102014E4"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:1224)
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:1589)



3.



Caused by: 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)


Incorrect Results:



Sat Oct 22 00:00:00 BST 2011
Thu Jan 22 00:00:00 GMT 1970
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010

Thu Oct 22 00:00:00 GMT 1970
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010


Correct Results:



Fri Oct 22 00:00:00 BST 2010

Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010
Fri Oct 22 00:00:00 BST 2010






Another approach to safely use DateFormats in a multi-threaded environment is to use a ThreadLocal variable to hold the DateFormat object, which means that each thread will have its own copy and doesn't need to wait for other threads to release it. This is how:



public class DateFormatTest {

private static final ThreadLocal df = new ThreadLocal(){
@Override
protected DateFormat initialValue() {

return new SimpleDateFormat("yyyyMMdd");
}
};

public Date convert(String source) throws ParseException{
Date d = df.get().parse(source);
return d;
}
}



Here is a good post with more details.


No comments:

Post a Comment

php - file_get_contents shows unexpected output while reading a file

I want to output an inline jpg image as a base64 encoded string, however when I do this : $contents = file_get_contents($filename); print ...