Heim >Java >JavaBase >Warum ist der Simpledateformat-Thread unsicher?

Warum ist der Simpledateformat-Thread unsicher?

青灯夜游
青灯夜游Original
2021-05-10 14:40:2417279Durchsuche

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.

Warum ist der Simpledateformat-Thread unsicher?

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!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn