Reprinted from: http://blog.csdn.net/zxh87/article/details/19414885
1. Conclusion
DateFormat and SimpleDateFormat are not thread-safe. Calling format () and parse () in a multithreaded environment should handle thread-safe issues.
2. Error example (1) Error Example 1
Each time information is processed, a new SimpleDateFormat instance is created, and then discarded. Cause a waste of memory.
1 PackageCom.peidasoft.dateformat;2 3 Importjava.text.ParseException;4 ImportJava.text.SimpleDateFormat;5 Importjava.util.Date;6 7 Public classDateutil {8 9 Public StaticString formatdate (date date)throwsparseexception{TenSimpleDateFormat SDF = new SimpleDateFormat("Yyyy-mm-dd HH:mm:ss"); One returnSdf.format (date); A } - - Public StaticDate Parse (String strdate)throwsparseexception{ theSimpleDateFormat SDF = new SimpleDateFormat("Yyyy-mm-dd HH:mm:ss"); - returnSdf.parse (strdate); - } -}
(2) Example error 2
To prevent frequent creation, using static SimpleDateFormat instances, all time-related processing uses this static instance.
The disadvantage is that there will be problems in the multithreaded environment, such as the wrong time of the conversion, the thread being hung dead or the strange error, and so on. is caused by simpledateformat thread insecurity.
1 PackageCom.peidasoft.dateformat;2 3 Importjava.text.ParseException;4 ImportJava.text.SimpleDateFormat;5 Importjava.util.Date;6 7 Public classDateutil {8 Private Static FinalSimpleDateFormat SDF =NewSimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");9 Ten Public StaticString formatdate (date date)throwsparseexception{ One returnSdf.format (date); A } - - Public StaticDate Parse (String strdate)throwsparseexception{ - returnSdf.parse (strdate); - } -}
3. Source code
Instructions for DateFormat in the JDK documentation:
The date format in SimpleDateFormat is not synchronized. It is recommended (recommended) to create a separate format instance for each thread. If multiple threads access a format at the same time, it must remain externally synchronized.
1 synchronization: 2 Not synchronized 3 for 4 synchronized externally.
SimpleDateFormat inherited the DateFormat. A Calendar class object is defined in DateFormat calendar. Because the concept of the calendar is complex, involving time zones and localization, and so on, the JDK implementation uses a member variable to pass parameters .
The format method is as follows:
1 Privatestringbuffer Format(date date, StringBuffer toappendto,2 Fielddelegate Delegate) {4 calendar.settime (date);6 BooleanUsedateformatsymbols =usedateformatsymbols ();7 8 for(inti = 0; I <compiledpattern.length;) {9 intTag = Compiledpattern[i] >>> 8;Ten intCount = compiledpattern[i++] & 0xff; One if(Count = = 255) { ACount = compiledpattern[i++] << 16; -Count |= compiledpattern[i++]; - } the - Switch(tag) { - CaseTag_quote_ascii_char: -Toappendto.append ((Char) count); + Break; - + CaseTag_quote_chars: A Toappendto.append (Compiledpattern, I, count); ati + =count; - Break; - - default: - Subformat (tag, count, delegate, Toappendto, usedateformatsymbols); - Break; in } - } to returntoappendto; +}
Calendar.settime (date) This statement changes the calendar, and later, the calendar is used (in the Subformat method), which is the root cause of the problem.
In a multithreaded environment, two threads hold an instance of the same simpledateformat, calling the Format method, respectively:
- Thread 1 calls the Format method, which changes the Calendar field.
- Interrupt.
- Thread 2 starts execution and it also changes the calendar.
- Interrupted again.
- Thread 1 is back, and at this point, the calendar is not the value it sets, and the error may occur if you proceed down.
If more than one thread competes for the Calendar object at the same time, there are various problems, such as incorrect timing, thread hangs, and so on.
There is a more important question behind this question-the state of being.
One of the benefits of a stateless approach is that it can be safely invoked in a variety of environments. To measure whether a method is stateful, see if it changes something else, such as a global variable, such as an instance field. The Format method changes the Calendar field of the SimpleDateFormat during the run, so it is stateful.
This also reminds us to note the next three points when developing and designing the system:
- When you write your own common class, the consequences of multi-threaded invocation are clearly stated in the comments.
- For a threading environment, be aware of the thread safety of each shared mutable variable.
- Our classes and methods are designed to be as stateless as possible.
4. Workaround (1) If you do not specifically consider performance, you can use the use of error example 1, each with a simpledateformat to create a new (2) If you consider performance, you want to use the form of Example 2 in error, you need to take additional synchronization measures
1 Public classDatesyncutil {2 3 Private StaticSimpleDateFormat SDF =NewSimpleDateFormat ("Yyyy-mm-dd HH:mm:ss");4 5 Public StaticString formatdate (date date)throwsparseexception{6 synchronized (SDF) {7 returnSdf.format (date);8 } 9 }Ten One Public StaticDate Parse (String strdate)throwsparseexception{ A synchronized(SDF) { - returnSdf.parse (strdate); - } the } -}
(3) If you want to consider performance more, you can use threadlocal
With threadlocal, the shared variable is also changed to exclusive, and the thread exclusive will certainly be able to reduce the overhead of creating objects in a concurrent environment in a concurrency-exclusive way. This approach is generally recommended if performance requirements are high.
Writing one:
1 PackageCom.peidasoft.dateformat;2 3 ImportJava.text.DateFormat;4 Importjava.text.ParseException;5 ImportJava.text.SimpleDateFormat;6 Importjava.util.Date;7 8 Public classConcurrentdateutil {9 Ten Private StaticThreadlocal<dateformat> ThreadLocal =NewThreadlocal<dateformat>() { One @Override A protectedDateFormat initialvalue() { - return NewSimpleDateFormat ("Yyyy-mm-dd HH:mm:ss"); - } the }; - - Public StaticDate Parse (String datestr)throwsParseException { - return threadlocal.get (). Parse (DATESTR); + } - + Public StaticString Format (date date) { A return threadlocal.get (). Format (date); at } -}
Two:
1 Public classThreadlocaldateutil {2 Private Static FinalString date_format = "Yyyy-mm-dd HH:mm:ss";3 Private StaticThreadlocal<dateformat> ThreadLocal =NewThreadlocal<dateformat>();
4 Public StaticDateFormat GetDateFormat (){ 6DateFormat DF =Threadlocal.get (); 7 if(df==NULL){ 8DF =NewSimpleDateFormat (Date_format); 9 Threadlocal.set (DF); Ten } One returnDF; A } - - Public StaticString formatdate (date date)throwsParseException { the returnGetDateFormat (). Format (date); - } - - Public StaticDate Parse (String strdate)throwsParseException { + returnGetDateFormat (). Parse (strdate); - } +}
5. Tests and conclusions
Do a simple stress test, one of the slowest methods, and the fastest method of the three.
But even the slowest method, a performance is not bad, the general system method one and two methods can be satisfied, so that in this point is difficult to become the bottleneck of the system. From a simple point of view, it is recommended to use method one or method two, if necessary, the pursuit of a bit of performance improvement, you can consider using method three, with threadlocal cache.
Ps:joda-time class Library is perfect for time processing, it is recommended. (to be studied)
Thread safety discussion for 2017.12.11SimpleDateFormat