Heim  >  Artikel  >  Ist der Hashset-Thread sicher?

Ist der Hashset-Thread sicher?

anonymity
anonymityOriginal
2019-04-25 13:38:4214206Durchsuche

Was ist Thread-Sicherheit? Das bedeutet, dass das Lesen und Schreiben von Daten threadisoliert sein sollte, was nicht zu Datenverlust oder Inkonsistenz führen sollte. Jedes Mal, wenn die Daten geändert werden, sollten sie nicht überschrieben werden.

Nehmen wir das klassische Beispiel einer Bankabhebung. Konto A liest zunächst 0, Thread A liest 0 und speichert dann 100 (Thread B liest noch 0 und speichert auch 100). Zeit Das letzte Konto, das wir sehen, ist ein Saldo von 100. Dies ist unwissenschaftlich und wird als Thread-unsicher bezeichnet. Daher müssen wir die Objekte für Ein- und Auszahlungen kontrollieren und die von uns betriebenen Objekte sperren lassen. Nach der Aktualisierung der Daten können andere Threads Thread-Sicherheit erreichen.

Ist der Hashset-Thread sicher?

Dieses Mal werden wir HashSet beweisen. Wir wissen, dass die Set-Schnittstelle implementiert ist. Das Merkmal von Set besteht darin, dass die gespeicherten Daten nicht wiederholt werden. Weil es zuerst die intern gespeicherten Daten liest, um zu sehen, ob sie vorhanden sind. Wenn sie vorhanden sind, werden sie nicht darin gespeichert, andernfalls werden sie darin gespeichert. Mit anderen Worten, der Datenspeichervorgang ist in zwei Schritte unterteilt: zuerst das Lesen und dann das Schreiben. Unter der Annahme, dass es nicht threadsicher ist, besteht eine sehr wahrscheinliche Situation darin, dass Thread B, wenn Thread A feststellt, dass das festgelegte Objekt kein Element hat und das Element einfügen möchte, auch feststellt, dass das Objekt nicht über das Element verfügt und dies der Fall ist Ich bereite auch das Einfügen vor. Das Ergebnis ist, dass zwei identische Elemente eingefügt werden.

Wir gestalten die Demo so:

class TestHashSet implements Runnable{
    // 实现Runnable 让该集合能被多个线程访问
    Set<Integer> set = new HashSet<Integer>();
    // 线程的执行就是插入5000个整数
    @Override
    public void run() {
        for (int i = 0;i < 5000;i ++) {
            set.add(i);
        }
    }
}

Wir testen sie im Hauptthread:

  TestHashSet run2 = new TestHashSet();
        // 实例化两个线程
        Thread t6 = new Thread(run2);
        Thread t7 = new Thread(run2);
        // 启动两个线程
        t6.start();
        t7.start();
        // 当前线程等待加入到调用线程后
        t6.join();
        t7.join();
        // 打印出集合的size
        System.out.println(run2.set.size());

Die meisten Druckergebnisse liegen bei den erwarteten 5000, aber gelegentlich gibt es solche ein Wert größer als 5000. . Dies führt zu der zuvor erwähnten Situation, die beweist, dass HashSet keine Thread-sichere Klasse ist.

Tatsächlich habe ich beim Betrachten des Quellcodes festgestellt, dass HashMap zur internen Verwaltung von Daten in HashSet verwendet wird. Der Hauptgrund dafür ist, dass HashMap keine Thread-sichere Klasse ist. Dies führt zur Nicht-Thread-Sicherheit von HashSet. Weitere Informationen zu Java-Sammlungsklassen finden Sie unter [Chinesische PHP-Website: Java-Video]

Abschließend noch eine vollständige Code-Fallüberprüfung:

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
 * 验证HashSet不是线程安全
 */
public class HashSetTest {
    public static void main(String[] args) {
        final Set<Integer> set = new HashSet<>();// 结果可能大于1000
//        final Set<Integer> set = Collections.synchronizedSet(new HashSet<>());// 结果等于1000
//        final Set<Integer> set = Collections.newSetFromMap(new ConcurrentHashMap<Integer, Boolean>());// 结果等于1000
        // 往set写入1-1000
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                for (int i = 1; i <= 1000; i++) {
                    set.add(i);
                }
            }
        };
        int threadNum = 10;// 线程数
        List<Thread> threadList = new ArrayList<>();
        for (int i = 0; i < threadNum; i++) {
            Thread thread = new Thread(runnable);
            threadList.add(thread);
            thread.start();
        }
        // 主线程等待子线程执行完成
        for (Thread thread : threadList) {
            try {
                thread.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(set.size());// 结果可能大于1000
    }
}

Das obige ist der detaillierte Inhalt vonIst der Hashset-Thread sicher?. 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