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, где ежедневно публикуется интересный контент.