This article has been published by the author Yao Taihang authorized Netease cloud community.
Welcome to the Netease cloud community to learn more about the operation experience of Netease technology products.
Simpledateformat is widely used in processing time formatting. Because this class specifies a pattern during creation to indicate a fixed time format, generally, an object with a large scope (static modification or a certain type of private property) is created for reuse. Due to the rare use cases of multi-thread concurrency encountered in the time conversion process, it is difficult to find hidden risks in this class. In fact, this class is not thread-safe, and format () is used in multithreading () and parse () methods may encounter problems.
Analysis
In the source file of simpledateformat and its parent class dateformat, the following description is provided:
* Date formats are not synchronized.* It is recommended to create separate format instances for each thread.* If multiple threads access a format concurrently, it must be synchronized* externally.
JDK documentation clearly states that these two classes are non-thread-safe during time formatting. That is to say, using the same simpledateformat instance to open several threads for date conversion operations may not be accurate.
Parse
For the parse () test, refer to other people's experiments on this. The test code I use (jdk1.8) is as follows:
import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;public class DateFormatTest extends Thread { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); private String name; private String dateStr; public DateFormatTest(String name, String dateStr) { this.name = name; this.dateStr = dateStr; } @Override public void run() { Date date = null; 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(); executor.execute(new DateFormatTest("Test_A", "2000-04-28")); executor.execute(new DateFormatTest("Test_B", "2017-04-28")); executor.shutdown(); }}
This test code references an online use case. The difference is that in the original use case, the thread waits for sleep in the middle of two thread operations. To see the effect, the modified test case removes the waiting part of the thread. Although the results of each run are not the same, exceptions are often thrown:
Exception in thread "pool-1-thread-1" java.lang.NumberFormatException: For input string: "" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) at java.lang.Long.parseLong(Long.java:601) at java.lang.Long.parseLong(Long.java:631) at java.text.DigitList.getLong(DigitList.java:195) at java.text.DecimalFormat.parse(DecimalFormat.java:2051) at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869) at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514) at java.text.DateFormat.parse(DateFormat.java:364) at DateFormatTest.run(DateFormatTest.java:24) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) at java.lang.Thread.run(Thread.java:745)Test_B : date: Mon Apr 28 00:00:00 CST 2200
It should be clear that the string to be converted is held by each object as a non-static private variable, and only the SDF itself is public. It is not hard to find that even if the output is successful, however, the value may not be correct, and the parse () method is not safe.
Format
The source code of the format () method of simpledateformat is as follows:
private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); ...
It should be noted that the calendar operation is not thread-safe. Obviously, in the concurrent scenario, the format is not safe to use. The test process is similar to the test of the parse process.
Solution
Since simpledateformat is not safe, there are two solutions: optimize the use process or find a substitute.
1. Temporary Creation
Static is not used. A new instance is created each time it is used.
Problems:
Simpledateformat uses the Calendar Object. Because the object is very heavy, a large number of new simpledateformat and simpledateformat will be destroyed in high concurrency, which is extremely resource-consuming.
2. Synchronized
Synchronize simpledateformat objects with synchronized.
Problems:
When the object is used for high concurrency, blocking occurs. When the current user is used, other users wait. Although the result is correct, the concurrency becomes a queue, which does not solve the problem, it also affects performance and efficiency.
3. threadlocal
Threadlocal is used to create a simpledateformat instance object for the current thread.
Problems:
When threadlocal is used, if the process of executing an atomic task is that each thread executes a task, such a declaration is basically no different from the instance object created before each use; if multi-thread and task queue is used, for example, tomcat has M processing threads and N external requests to be processed, when n tasks are executed, in fact, only M simpledateformat instances will be created. For a single processing thread, the execution tasks are ordered, so there is no concurrency for the current thread.
4. Apache dateformatutils and fastdateformat
Use org. Apache. commons. Lang. Time. fastdateformat and org. Apache. commons. Lang. Time. dateformatutils.
Problems:
Apache ensures thread security and is more efficient. However, the dateformatutils and fastdateformat classes only have the format () method. All the format methods only accept long, date, and calendar input and convert them to time strings. Currently, parse () does not exist () method, which can be converted from a time string to a time object.
5. joda-time
Use the joda-time class library.
Problems:
No problem ~
Introduction:
Joda-time-an alternative to the date/time library for Java applications. joda-time makes time and date values easy to manage, operate, and understand. In fact, ease of use is the main design goal of joda. Other goals include scalability, complete feature sets, and support for multiple calendar systems. In addition, joda and JDK are interoperable. Therefore, you do not need to replace all the Java code, but only the part of the Code that executes the date/time calculation.
MATERIALS:
Joda-time introduction https://www.ibm.com/developerworks/cn/java/j-jodatime.html
Joda-time document (English) http://joda-time.sourceforge.net/
"If you want to see it, pay attention everywhere ." -Song fan
Free trial of cloud security (yundun) content security, verification code and other services
For more information about Netease technologies, products, and operations, click.
Related Articles:
[Recommendation] Netease cloud database architecture design practices
[Recommended] JQ is a powerful JSON format viewing tool.
Simpledateformat concurrency risks and Solutions