SimpleDateFormat thread safety issues and solutions

Source: Internet
Author: User
Tags locale

SimpleDateFormat Thread-safety issues

SimpleDateFormat is a specific class that formats and analyzes data in a country-sensitive manner. It allows formatting (date-and-text), parsing (text, date), and normalization.

But SimpleDateFormat is not a thread-safe class, and there is a problem with multi-threaded concurrent access. Verify with the following code,

public class Provenotsafe {static SimpleDateFormat df = new SimpleDateFormat ("dd-mmm-yyyy", locale.us); static String test Data[] = {"01-jan-1999", "14-feb-2001", "31-dec-2007"};p ublic static void Main (string[] args) {Runnable r[] = new Runnab le[testdata.length];for (int i = 0; i < r.length; i++) {final int i2 = i;r[i] = new Runnable () {public void run () {try {for (int j = 0; J <; J + +) {String str = testdata[i2]; String str2 = null;/* synchronized (DF) */{date d = df.parse (str); str2 = Df.format (d); System.out.println ("I:" + I2 + "\TJ:" + j+ "\tthreadid:" + thread.currentthread (). GetId () + "\tthreadname:" + Thread.curr Entthread (). GetName () + "\ T" + str + "\ T" + str2);} if (!str.equals (str2)) {throw new RuntimeException ("date conversion failed after" + j+ "iterations.) Expected "+ str +" but got "+ str2);}}} catch (ParseException e) {throw new RuntimeException ("Parse Failed");}}; New Thread (R[i]). Start ();}}

Run multiple times, an exception error occurs:

Java.lang.RuntimeException:date conversion failed after 0 iterations. Expected 01-jan-1999 but got 28-jul-2015

Thread access is generally the case:


Within the SimpleDateFormat class, there is a Calendar object reference, which is used to store date information related to this simpledateformat, such as Sdf.parse (DATESTR), Sdf.format (date) And so on. The date-dependent string passed to the parameter, date, and so on, are given to Calendar for storage. This can cause a problem if your simpledateformat is static, so multiple thread The SimpleDateFormat is shared and the calendar reference is shared, and there is a time-disordered situation.


Workaround
(1) The first method is also the simplest solution. We can remove the static so that each new thread will have its own SDF instance to avoid thread-safety problems.

SimpleDateFormat df = new SimpleDateFormat ("dd-mmm-yyyy", locale.us);D ate d = df.parse (str); str2 = Df.format (d);

At this point, the following conditions are accessed:


However, with this approach, it is very resource-intensive to have a large number of new SDF and destroy SDF in highly concurrent situations.


(2) The second method, the use of ThreadLocal.

In the case of concurrency, the request task of a Web site and the execution of a thread are probably understood as follows.


For example, Tomcat's thread pool has a maximum thread count of 4 and now needs to perform 1000 tasks (understood to have 1000 users point to a feature of your site), and these 1000 tasks will use the DATE function processing class we wrote

A) If the Date function processing class is using the new SimpleDateFormat method, then there will be 1000 SDF creation and destruction

B) Java provides a threadlocal solution that works by having only one instance per thread, which means that we're only going to instantiate 4 SDF in a total of 1000 tasks.

Also, it does not have multithreading concurrency problems. Because a single thread performs a task that must be sequential, such as a thread #1负责执行Task #1-#250, then he executes the task #1-#250, and the thread #2拥有自己的sdf实例, he is also the task #251 in order to perform tasks-#500, And so on

/* */package Org.bupt.xiaoye.chapter3;import java.text.parseexception;import Java.text.simpledateformat;import Java.util.date;import Java.util.hashmap;import Java.util.map;public class Dateutil {/**) SDF Map */private with different date template formats Static threadlocal<map<string, simpledateformat>> Sdfmap = new threadlocal<map<string, Simpledateformat>> () {@Overrideprotected map<string, simpledateformat> InitialValue () { System.out.println (Thread.CurrentThread (). GetName () + "init pattern:" + thread.currentthread ()); return new HashMap <string, simpledateformat> ();}};/ * * Returns a simpledateformat, each thread will only be new once the pattern corresponding SDF * * @param pattern * @return */private static SimpleDateFormat getsdf ( Final String pattern) {map<string, simpledateformat> tl = Sdfmap.get (); SimpleDateFormat SDF = Tl.get (pattern), if (SDF = = null) {System.out.println (Thread.CurrentThread (). GetName () + "put new SDF of pattern + pattern + "to map"); SDF = new SimpleDateFormat (pattern); Tl.put (Pattern, SDF);} return SDF;} /** * so that each thread will have only one SimpleDateFormat * * @param date * @param pattern * @return */public static String format (date date, Str ing pattern) {return getsdf (pattern). Format (date);} public static Date Parse (string datestr, String pattern) throws ParseException {return getsdf (pattern). Parse (DATESTR);}}

Each thread here has a map table with thread key, and this table is a pattern key, and each pattern has a unique SimpleDateFormat object.

We test it with the following code:

Package Org.bupt.xiaoye.chapter3;import Java.text.parseexception;import Java.util.concurrent.ExecutorService; Import Java.util.concurrent.executors;import Java.util.concurrent.timeunit;public class Test {public static void main (        String[] (args) {final String patten1 = "YYYY-MM-DD";        Final String patten2 = "yyyy-mm"; Thread t1 = new Thread () {@Override public void run () {try {Dat                Eutil.parse ("1992-09-13", patten1);                } catch (ParseException e) {e.printstacktrace ();        }            }        }; Thread t2 = new Thread () {@Override public void run () {try {Dat                Eutil.parse ("2000-09", patten2);                } catch (ParseException e) {e.printstacktrace ();        }            }        };       thread t3 = new Thread () {@Override public void run () {         try {dateutil.parse ("1992-09-13", patten1);                } catch (ParseException e) {e.printstacktrace ();        }            }        }; Thread T4 = new Thread () {@Override public void run () {try {Dat                Eutil.parse ("2000-09", patten2);                } catch (ParseException e) {e.printstacktrace ();        }            }        }; Thread T5 = new Thread () {@Override public void run () {try {Dat                Eutil.parse ("2000-09-13", patten1);                } catch (ParseException e) {e.printstacktrace ();        }            }        }; Thread T6 = new Thread () {@Override public void run () {try {Dat                Eutil.parse ("2000-09", patten2); } catch (ParseException e) {E.PRintstacktrace ();        }            }        };        SYSTEM.OUT.PRINTLN ("Single Thread Execution:");        Executorservice exec = Executors.newfixedthreadpool (1);        Exec.execute (t1);        Exec.execute (T2);        Exec.execute (T3);        Exec.execute (T4);        Exec.execute (T5);        Exec.execute (T6);        Exec.shutdown ();        Sleep (1000);        System.out.println ("Double-threaded execution:");        Executorservice exec2 = Executors.newfixedthreadpool (2);        Exec2.execute (t1);        Exec2.execute (T2);        Exec2.execute (T3);        Exec2.execute (T4);        Exec2.execute (T5);        Exec2.execute (T6);    Exec2.shutdown ();        } private static void sleep (long millsec) {try {TimeUnit.MILLISECONDS.sleep (millsec);        } catch (Interruptedexception e) {e.printstacktrace (); }    }}

Single Thread execution: pool-1-thread-1 init pattern:thread[pool-1-thread-1,5,main]pool-1-thread-1 put new SDF of pattern YYYY-MM-DD to Ma Ppool-1-thread-1 put new SDF of pattern yyyy-mm to map dual-threaded execution: pool-2-thread-1 init pattern:thread[pool-2-thread-1,5,main]p Ool-2-thread-1 put new SDF of pattern yyyy-mm-dd to mappool-2-thread-2 init pattern:thread[pool-2-thread-2,5,main]pool-2 -thread-2 put new SDF of pattern yyyy-mm to mappool-2-thread-1 put new SDF's pattern yyyy-mm to mappool-2-thread-2 put NE W SDF of pattern YYYY-MM-DD to map

From the output we can see:

1) When 1 threads perform these 6 tasks, the thread will use the new SDF for the first time, and use this SDF in the future instead of creating a new SDF every time the task is processed.

2) 2 threads perform 6 tasks at the same time, but 2 threads of SDF are separate, each thread has its own "yyyy-mm-dd", "yyyy-mm" SDF, so they will not thread security security issues

Imagine that if you are using the new implementation method, whether it is 1 threads to execute, or 2 threads to perform these 6 tasks, all need new 6 SDF


(3) The third way, use the synchronous code block (synchronized) or use the adorner design pattern to wrap the SimpleDateFormat, making it thread-safe.

That is, the instance closure mechanism described in another article.

http://blog.csdn.net/zq602316498/article/details/40143437


(4) Fourth Way, using third-party date processing functions

For example JODA to avoid these problems, you can also use the Fastdateformat tool class in the Commons-lang package.


Reference blog:

http://my.oschina.net/leejun2005/blog/152253

Http://www.cnblogs.com/zemliu/archive/2013/08/29/3290585.html



SimpleDateFormat thread safety issues and solutions

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.