SimpleDateFormat не является потокобезопасным
хорошо известныйSimpleDateFormatНить небезопасна, и многие друзья были стравлены ею.
Вот статья о стекеwhy-is-javas-simpledateformat-not-thread-safeкаштанов.
public class ExampleClass {
private static final Pattern dateCreateP = Pattern.compile("Дата подачи:\\s*(.+)");
private static final SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss dd.MM.yyyy");
public static void main(String[] args) {
ExecutorService executor = Executors.newFixedThreadPool(100);
while (true) {
executor.submit(new Runnable() {
@Override
public void run() {
workConcurrently();
}
});
}
}
public static void workConcurrently() {
Matcher matcher = dateCreateP.matcher("Дата подачи: 19:30:55 03.05.2015");
Timestamp startAdvDate = null;
try {
if (matcher.find()) {
String dateCreate = matcher.group(1);
startAdvDate = new Timestamp(sdf.parse(dateCreate).getTime());
}
} catch (Throwable th) {
th.printStackTrace();
}
System.out.print("OK ");
}
}
And result :
OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK OK java.lang.NumberFormatException: For input string: ".201519E.2015192E2"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
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 com.nonscalper.webscraper.processor.av.ExampleClass.workConcurrently(ExampleClass.java:37)
at com.nonscalper.webscraper.processor.av.ExampleClass$1.run(ExampleClass.java:25)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
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)
решение
-
Каждый
new(создать экземпляр)SimpleDateFormat. -
использовать
ThreadLocalУбедитесь, что каждый поток может получить отдельныйSimpleDateFormat.
public class DateUtil {
private static final ThreadLocal<SimpleDateFormat> local = ThreadLocal.withInitial(() -> new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));
public static String format(Date date) {
return local.get().format(date);
}
public static Date parse(String dateStr) throws ParseException {
return local.get().parse(dateStr);
}
}
-
commons-lang3серединаFastDateFormat.
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang3-version}</version>
</dependency>
конкурс производительности
Как насчет производительности, приходит jmh, смотрите исходный код:GitHub.com/lets-mica/no…
# JMH version: 1.21
# VM version: JDK 1.8.0_221, Java HotSpot(TM) 64-Bit Server VM, 25.221-b11
Benchmark Mode Cnt Score Error Units
newSimpleDateFormat thrpt 5 114072.841 ± 989.135 ops/s
threadLocal thrpt 5 348207.331 ± 46014.175 ops/s
fastDateFormat thrpt 5 434391.553 ± 7799.593 ops/s
результат:fastDateFormatСамый высокий балл. Вы, конечно, думаете, что это конец?
Используйте Instant + DateTimeFormatter
существуетmica 1.2.1мы используемInstantтранзитDateиспользоватьDateTimeFormatterформат.
public static final DateTimeFormatter DATETIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneId.systemDefault());
public String format(Date date) {
return DATETIME_FORMATTER.format(date.toInstant());
}
Уведомление:DateTimeFormatterформатInstantнеобходимо указатьЧасовой пояс.
результаты стресс-теста jdk 8
# JMH version: 1.21
# VM version: JDK 1.8.0_221, Java HotSpot(TM) 64-Bit Server VM, 25.221-b11
Benchmark Mode Cnt Score Error Units
fastDateFormat thrpt 5 417338.980 56543.104 ops/s
toInstantFormat thrpt 5 371028.709 72059.917 ops/s
результаты стресс-теста jdk 11
# JMH version: 1.21
# VM version: JDK 11.0.4, OpenJDK 64-Bit Server VM, 11.0.4+10-b304.69
Benchmark Mode Cnt Score Error Units
fastDateFormat thrpt 5 384637.138 7402.690 ops/s
toInstantFormat thrpt 5 487482.436 12490.986 ops/s
в заключении
использоватьDateTimeFormatter + Instantсуществуетjava8Сяхэcommons-lang3серединаFastDateFormatЭто близко, более высокая версияjdkВыдающийся.
Если вы используете более позднюю версиюjdkИли рассмотрите возможность обновления до более высокой версии позжеJDK, этот метод является хорошим выбором.
Добро пожаловать, чтобы обратить внимание на наш общедоступный аккаунт: Dream Technology, где ежедневно публикуется интересный контент.