https://www.cnblogs.com/zemliu/p/3290585.html
https://www.cnblogs.com/peida/archive/2013/05/31/3070790.html
1. Cause
The SimpleDateFormat (hereinafter referred sdf) Calendar object class has an internal reference, which is used to store the sdf and related date information, e.g. sdf.parse (dateStr), sdf.format (date) like method parameters related to the incoming date String , Date, etc., are stored in a reference to the Friends Calendar. this will cause a problem if your sdf is static, then this will be shared between multiple sdf thread, but also share the Calendar references, and, observation sdf.parse () method, you will find the following call:
The parse DATE () { calendar.clear (); // Cleanup calendar ... // perform some operations date, the calendar is provided what calendar.getTime (); // Get time calendar }
When this can cause problems is, if thread A calls sdf.parse (), and were calendar.clear () has not been executed calendar.getTime (), the thread B calls the sdf.parse (), which when the thread B executed also sdf.clear () method, thus leading to the thread a calendar data is emptied (in fact a, B are simultaneously cleared). or the a executed calendar.clear () when is suspended, this time B starts calling sdf.parse () and end smoothly i, date stored in the calendar this into a and B later date calendar settings
2. to reproduce the problem
import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; /** * @author zhenwei.liu created on 2013 13-8-29 下午5:35 * @version $Id$ */ public class DateFormatTest extends Thread { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); private String name; private String dateStr; private boolean sleep; public DateFormatTest(String name, String dateStr, boolean sleep) { this.name = name; this.dateStr = dateStr; this.sleep = sleep; } @Override public void run() { Date date = null; if (sleep) { try { TimeUnit.MILLISECONDS.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } try { date = sdf.parse(dateStr); } catch (ParseException e) { e.printStackTrace(); } System.out.println(name + " : date: " + date); } public static void main(String[] args) throws InterruptedException { ExecutorService executor = Executors.newCachedThreadPool (); started sdf.parse () // A will after 2S SLEEP Executor.execute (new new DateFormatTest ( "A", "1991-09-13", to true)); // play B a breakpoint, the method will be stuck in the middle Executor.execute (new new DateFormatTest ( "B", "2013-09-13", to false)); executor.shutdown (); } }
Use this code Debug mode execution, and marked with a breakpoint in sdf.parse () method in
the parse () { calendar.clear () // hit a breakpoint where calendar.getTime () }
process:
1) A first thread will enter sleep after run up
2) B threads run up the card at the breakpoint
3) A thread wake up, execution calendar.clear (), and the date is set sdf.calendar 1991-09-13, calendar at this time are the AB 1991-09-13
4) Let the breakpoint continue, the following output
A : date: Fri Sep 13 00:00:00 CDT 1991
B : date: Fri Sep 13 00:00:00 CDT 1991
This is not what we expect results
3. Solution
The most simple solution we can get rid of the static, so that each new thread will have its own sdf example, in order to avoid thread-safety issues
However, using this method, in the case of high concurrency will be a lot of new sdf and destroy sdf, this can be very resource-intensive
In the case of concurrent requests the implementation of tasks and threads about the site can be understood as follows
Such as the maximum number Thread Tomcat thread pool is 4, you need to perform the task now has 1000 (understood to have 1,000 users point to a function of your website),
This 1000 mission will be used in processing class date functions we write
A) If you say date functions like processing method using a new SimpleDateFormat, this will be the creation and destruction of 1000 sdf
B) Java ThreadLocal to provide a solution, the way it works is that each thread will be only one instance, that is to say we finished the implementation of the 1000 mission, a total of only four instances of sdf.
Moreover, it does not issue multiple concurrent threads, because a single thread is definitely the order of tasks, such as Thread # 1 is responsible for the implementation of Task # 1- # 250, then he is sequentially executed Task # 1- # 250
The Thread # 2 has its own sdf instance, he is also the order of tasks Task # 251- # 500, and so on
III. Solution
1. Create a new instance of time needed:
package com.peidasoft.dateformat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateUtil { public static String formatDate(Date date)throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.format(date); } public static Date parse(String strDate) throws ParseException{ SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); return sdf.parse(strDate); } }
Description: Create a new instance of SimpleDateFormat is used where it is needed, no matter what time, there will be thread-safety issues by the shared object into a local private can avoid multi-threading issues, but also increased the burden of creating an object. In general, this is actually not very significant impact on the performance ratio.
2. Sync: Synchronization Object SimpleDateFormat
package com.peidasoft.dateformat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class DateSyncUtil { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); public static String formatDate(Date date)throws ParseException{ synchronized(sdf){ return sdf.format(date); } } public static Date parse(String strDate) throws ParseException{ synchronized(sdf){ return sdf.parse(strDate); } } }
Description: When there are many threads, when a thread calls this method, other threads want to call this method will block, to a certain extent multi-threaded large amount of time on performance.
3. Use ThreadLocal:
package com.peidasoft.dateformat; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class ConcurrentDateUtil { private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>() { @Override protected DateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; public static Date parse(String dateStr) throws ParseException { return threadLocal.get().parse(dateStr); } public static String format(Date date) { return threadLocal.get().format(date); } }
Another way to write:
package com.peidasoft.dateformat; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; public class ThreadLocalDateUtil { private static final String date_format = "yyyy-MM-dd HH:mm:ss"; private static ThreadLocal<DateFormat> threadLocal = new ThreadLocal<DateFormat>(); public static DateFormat getDateFormat() { DateFormat df = threadLocal.get(); if(df==null){ df = new SimpleDateFormat(date_format); threadLocal.set(df); } return df; } public static String formatDate(Date date) throws ParseException { return getDateFormat().format(date); } public static Date parse(String strDate) throws ParseException { return getDateFormat().parse(strDate); } }
Description: Use ThreadLocal, but also the shared variable becomes exclusive, exclusive thread certainly exclusive method than in a concurrent environment can reduce a lot of the overhead of creating objects. If is relatively high on the performance requirements, it is generally recommended to use this method.
Here is an example using ThreadLocal solve the problem of multi-threaded sdf