Here’s an example defines a SimpleDateFormat object as a static field. When two or more threads access “someMethod” concurrently with different dates, they can mess with each other’s results.
public class SimpleDateFormatExample { private static final SimpleDateFormat simpleFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); public String someMethod(Date date) { return simpleFormat.format(date); } }
You can create a service like below and use jmeter to simulate concurrent users using the same SimpleDateFormat object formatting different dates and their results will be messed up.
public class FormattedTimeHandler extends AbstractHandler { private static final String OUTPUT_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss.SSS"; private static final String INPUT_TIME_FORMAT = "yyyy-MM-ddHH:mm:ss"; private static final SimpleDateFormat simpleFormat = new SimpleDateFormat(OUTPUT_TIME_FORMAT); // apache commons lang3 FastDateFormat is threadsafe private static final FastDateFormat fastFormat = FastDateFormat.getInstance(OUTPUT_TIME_FORMAT); public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { response.setContentType("text/html;charset=utf-8"); response.setStatus(HttpServletResponse.SC_OK); baseRequest.setHandled(true); final String inputTime = request.getParameter("time"); Date date = LocalDateTime.parse(inputTime, DateTimeFormat.forPattern(INPUT_TIME_FORMAT)).toDate(); final String method = request.getParameter("method"); if ("SimpleDateFormat".equalsIgnoreCase(method)) { // use SimpleDateFormat as a static constant field, not thread safe response.getWriter().println(simpleFormat.format(date)); } else if ("FastDateFormat".equalsIgnoreCase(method)) { // use apache commons lang3 FastDateFormat, thread safe response.getWriter().println(fastFormat.format(date)); } else { // create new SimpleDateFormat instance when formatting date, thread safe response.getWriter().println(new SimpleDateFormat(OUTPUT_TIME_FORMAT).format(date)); } } public static void main(String[] args) throws Exception { // embedded jetty configuration, running on port 8090. change it as needed. Server server = new Server(8090); server.setHandler(new FormattedTimeHandler()); server.start(); server.join(); }
}
The code and jmeter script can be downloaded here .
formatandparsemethods to be threadsafe once the format and timezone are set. Currently I am searching and fixing all those SimpleDateFormat usages in our codebase :/DateFormat,SimpleDateFormat,Date, andCalendarclasses. These terrible classes are all legacy now. They were supplanted years ago by the modern java.time classes defined in JSR 310. The java.time classes are thread-safe by design, using immutable objects.