Ursache: Wenn in einer Multithread-Umgebung mehrere Threads gleichzeitig dasselbe SimpleDateFormat-Objekt verwenden (z. B. statische Änderung), z. B. beim Aufrufen der Formatmethode, rufen mehrere Threads gleichzeitig die Methode Calendar.setTime auf , was dazu führt, dass andere Threads Zeit verbrauchen. Geändert, sodass es Thread-unsicher ist.
Die Betriebsumgebung dieses Tutorials: Windows7-System, Java8-Version, DELL G3-Computer.
Thread-Unsicherheitsüberprüfung:
/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest { private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() { while (true) { poolExecutor.execute(new Runnable() { @Override public void run() { String dateString = simpleDateFormat.format(new Date()); try { Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); } catch (ParseException e) { e.printStackTrace(); } } }); } }
Ausgabe:
true false true true false
false erscheint, was darauf hinweist, dass der Thread unsicher ist
1. Formatmethode
public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition pos) { pos.beginIndex = pos.endIndex = 0; return format(date, toAppendTo, pos.getFieldDelegate()); } // Called from Format after creating a FieldDelegate private StringBuffer format(Date date, StringBuffer toAppendTo, FieldDelegate delegate) { // Convert input date to time field list calendar.setTime(date); boolean useDateFormatSymbols = useDateFormatSymbols(); for (int i = 0; i < compiledPattern.length; ) { int tag = compiledPattern[i] >>> 8; int count = compiledPattern[i++] & 0xff; if (count == 255) { count = compiledPattern[i++] << 16; count |= compiledPattern[i++]; } switch (tag) { case TAG_QUOTE_ASCII_CHAR: toAppendTo.append((char)count); break; case TAG_QUOTE_CHARS: toAppendTo.append(compiledPattern, i, count); i += count; break; default: subFormat(tag, count, delegate, toAppendTo, useDateFormatSymbols); break; } } return toAppendTo; }
protected Calendar calendar;
Sie können sehen, dass der variable Kalender von mehreren Threads gemeinsam genutzt wird und der Kalender es ist geändert. Wenn daher in einer Multithread-Umgebung mehrere Threads gleichzeitig dasselbe SimpleDateFormat-Objekt verwenden (z. B. statische Änderung), z. B. beim Aufrufen der Formatmethode, rufen mehrere Threads gleichzeitig die Methode calender.setTime auf, was dazu führt Zeit, von anderen Threads geändert zu werden. Daher sind Threads nicht sicher.
Darüber hinaus ist die Parse-Methode auch Thread-unsicher. Die Parse-Methode ruft tatsächlich CalenderBuilder zum Parsen auf. Die Hauptschritte in ihrer Methode sind keine atomaren Operationen.
Lösung:
1. Definieren Sie SimpleDateFormat als lokale Variable
2. Fügen Sie eine Thread-Synchronisationssperre hinzu: synchronisiert(lock)
3. Mit ThreadLocal verfügt jeder Thread über eine eigene Kopie des SimpleDateFormat-Objekts. Zum Beispiel:
/** * SimpleDateFormat线程安全测试 * 〈功能详细描述〉 * * @author 17090889 * @see [相关类/方法](可选) * @since [产品/模块版本] (可选) */ public class SimpleDateFormatTest { private static final ThreadLocal<SimpleDateFormat> THREAD_LOCAL = new ThreadLocal<SimpleDateFormat>() { @Override protected SimpleDateFormat initialValue() { return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } }; // private SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(10, 100, 1, TimeUnit.MINUTES, new LinkedBlockingQueue<>(1000), new MyThreadFactory("SimpleDateFormatTest")); public void test() { while (true) { poolExecutor.execute(new Runnable() { @Override public void run() { SimpleDateFormat simpleDateFormat = THREAD_LOCAL.get(); if (simpleDateFormat == null) { simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); } String dateString = simpleDateFormat.format(new Date()); try { Date parseDate = simpleDateFormat.parse(dateString); String dateString2 = simpleDateFormat.format(parseDate); System.out.println(dateString.equals(dateString2)); } catch (ParseException e) { e.printStackTrace(); } finally { local.remove(); } } }); } } }
4. Verwenden Sie DateTimeFormatter anstelle von SimpleDateFormat
DateTimeFormatter ist threadsicher und bietet standardmäßig viele Formatierungsmethoden, die auch über die ofPattern-Methode erstellt werden können.
(1) Format-Datumsbeispiel:
LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDateTime); // 2019-11-20T15:04:29.017 DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); String strDate=localDateTime.format(dtf); System.out.println(strDate); // 2019/23/20 15:23:46
(2) Parse-Datum
DateTimeFormatter dtf=DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); LocalDateTime localDateTime=LocalDateTime.parse("2019/11/20 15:23:46",dtf); System.out.println(localDateTime); // 2019-11-20T15:23:46
Empfohlene verwandte Video-Tutorials: Java-Video-Tutorial
Das obige ist der detaillierte Inhalt vonWarum ist der Simpledateformat-Thread unsicher?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!