Heim  >  Artikel  >  Java  >  So implementieren Sie Thread-Sicherheit in der gleichzeitigen Java-Programmierung

So implementieren Sie Thread-Sicherheit in der gleichzeitigen Java-Programmierung

WBOY
WBOYnach vorne
2023-05-21 15:14:131484Durchsuche

    1. Was ist Thread-Sicherheit?

    Wenn mehrere Threads auf eine Klasse zugreifen, unabhängig davon, welche Aufrufmethode die Laufzeitumgebung verwendet oder wie diese Threads abwechselnd ausgeführt werden, ist im Hauptaufrufcode nichts erforderlich Diese Klasse kann trotz zusätzlicher Synchronisierung oder Koordination korrektes Verhalten zeigen, dann wird diese Klasse als Thread-sicher bezeichnet.

    Zustandslose Objekte müssen Thread-sicher sein, wie zum Beispiel: Servlet. Servlet

    2.原子性

    2.1 竞争条件

    由于不恰当的执行时序而出现不正确的结果的情况,就是竞争条件。

    “先检查后执行”操作,即通过一个可能实效的观测结果来决定下一步的动作。比如:延迟初始化。

    if(instance == null) {
        instance = new SomeObject();
    }

    “读取-修改-写入”的操作,其结果状态依赖于之前的状态。如:递增运算。

    long count = 0;
    count++;

    2.2 复合操作

    原子操作是指,对于访问同一个状态的所有操作(包括此操作本身)来说,这个操作是以一个原子方式执行(不可分割)的操作。

    为了确保线程安全性,包含了一组必须以原子方式执行的操作,称为复合操作。

    递增运算可以使用一个现有的线程安全类,确保线程安全性。如:

    AtomicLong count = new AtomicLong(0);
    count.incrementAndGet();

    3.加锁机制

    如果一个类只有一个状态变量,可以通过使用线程安全的状态变量来确保类的线程安全性。当一个类有更多的状态时,仅仅添加更多的线程安全状态变量是不够的。为了确保状态的一致性,必须在单个原子操作中更新所有相关的状态变量。

    3.1 内置锁

    Java提供一种内置锁:同步代码块,它包括:一个作为锁的对象引用、一个作为由这个锁保护的代码块。

    以关键字synchronized来修饰的方法就是一种横跨整个方法体的同步代码块,其中该同步代码块的锁就是方法调用所在的对象。静态的synchronized

    2. Atomizität

    2.1 Rennbedingung

    Eine Rennbedingung liegt vor, wenn aufgrund einer falschen Ausführungszeit falsche Ergebnisse auftreten.

    Die Operation „Zuerst prüfen und dann ausführen“ besteht darin, die nächste Aktion auf der Grundlage eines möglichen und wirksamen Beobachtungsergebnisses zu bestimmen. Zum Beispiel: verzögerte Initialisierung.

    public class Widget {
        public synchronized void doSomething() {
            //......
        }
    }
    public class LoggingWidget extends Widget {
        public synchronized void doSomething() {
            //......
            super.doSomething();//假如没有可重入的锁,该语句将产生死锁。
        }
    }

    „Read-Modify-Write“-Operation, der Ergebniszustand hängt vom vorherigen Zustand ab. Zum Beispiel: Inkrementierungsvorgang.

    @ThreadSafe
    public class SynchronizedFactorizer implements Servlet {
        @GuardedBy("this") private BigInteger lastNumber;
        @GuardedBy("this") private BigInteger[] lastFactors;
    
        public synchronized void service(ServletRequest req,
                                         ServletResponse resp) {
            BigInteger i = extractFromRequest(req);
            if (i.equals(lastNumber))
                encodeIntoResponse(resp, lastFactors);
            else {
                BigInteger[] factors = factor(i);//因数分解计算
                lastNumber = i;
                lastFactors = factors;//存放上一次计算结果
                encodeIntoResponse(resp, factors);
            }
        }
    }

    2.2 Zusammengesetzte Operation

    Atomere Operation bedeutet, dass für alle Operationen, die auf denselben Status zugreifen (einschließlich der Operation selbst), diese Operation auf atomare Weise (unteilbar) ausgeführt wird.

    Um die Thread-Sicherheit zu gewährleisten, ist eine Reihe von Operationen enthalten, die atomar ausgeführt werden müssen, sogenannte zusammengesetzte Operationen.

    Inkrementelle Vorgänge können eine vorhandene Thread-sichere Klasse verwenden, um die Thread-Sicherheit zu gewährleisten. Zum Beispiel:

    public class CachedFactorizer implements Servlet {
        @GuardedBy("this") private BigInteger lastNumber;
        @GuardedBy("this") private BigInteger[] lastFactors;
    
        public void service(ServletRequest req, ServletResponse resp) {
            BigInteger i = extractFromRequest(req); 
            BigInteger[] factors = null;      
            synchronized (this) {
                if (i.equals(lastNumber)) {
                   factors = lastFactors.clone();
                }         
            }    
            if (factors == null) {        
                factors = factor(i);
                synchronized (this) {
                   lastNumber = i;
                   lastFactors = factors.clone();
                }
            }
            encodeIntoResponse(resp, factors);
        }
    }

    3. Sperrmechanismus🎜🎜Wenn eine Klasse nur eine Statusvariable hat, können Sie die Thread-Sicherheit der Klasse sicherstellen, indem Sie threadsichere Statusvariablen verwenden. Wenn eine Klasse über mehr Status verfügt, reicht es nicht aus, einfach weitere threadsichere Statusvariablen hinzuzufügen. Um die Zustandskonsistenz sicherzustellen, müssen alle relevanten Zustandsvariablen in einer einzigen atomaren Operation aktualisiert werden. 🎜🎜3.1 Integrierte Sperre🎜🎜Java bietet eine integrierte Sperre: Synchronisierter Codeblock, er umfasst: Eine Objektreferenz als Sperre und einen Code als geschützt durch dieses Schlossstück. 🎜🎜Die mit dem Schlüsselwort synchronized geänderte Methode ist ein synchronisierter Codeblock, der den gesamten Methodenkörper umfasst, und die Sperre des synchronisierten Codeblocks ist das Objekt, in dem die Methode aufgerufen wird. Die statische synchronized-Methode verwendet das Class-Objekt als Sperre. 🎜🎜Wenn ein Thread einen synchronisierten Codeblock betritt, erhält er automatisch die Sperre, und wenn der Thread den synchronisierten Codeblock verlässt, wird die Sperre automatisch freigegeben. Maximal ein Thread kann diese Sperre halten, sodass synchronisierter Code atomar ausgeführt wird. 🎜🎜3.2 Wiedereintrittsfähigkeit🎜🎜Die integrierte Sperre ist wiedereintrittsfähig, was bedeutet, dass die Granularität der Operation zum Erlangen der Sperre der Thread und nicht der Aufruf ist. Wenn ein Thread versucht, eine bereits von ihm gehaltene Sperre erneut zu erhalten, ist die Anforderung ebenfalls erfolgreich. 🎜🎜Reentrancy verbessert die Kapselung des Sperrverhaltens weiter und vereinfacht die Entwicklung von objektorientiertem gleichzeitigem Code. 🎜rrreee🎜4. Schützen Sie den Status mit einer Sperre🎜🎜Für eine variable Statusvariable, auf die mehrere Threads gleichzeitig zugreifen können, müssen Sie beim Zugriff darauf die gleiche Sperre beibehalten durch diese Sperre geschützt gesteuert werden. 🎜🎜5. Lebendigkeit und Leistung🎜🎜Die grobkörnige Verwendung von Sperren gewährleistet die Thread-Sicherheit, kann jedoch zu Leistungsproblemen und Lebendigkeitsproblemen führen, wie zum Beispiel: 🎜rrreee🎜Sie können sicherstellen, dass das Servlet konsistent ist, indem Sie die Blockfrisur des Synchronisationscodes verkleinern , unter Beibehaltung der Thread-Sicherheit. Teilen Sie nicht atomare Vorgänge in mehrere synchronisierte Codeblöcke auf. Versuchen Sie, Vorgänge, die keinen Einfluss auf den gemeinsamen Status haben und deren Ausführung lange dauert, vom synchronisierten Code zu trennen. Wie zum Beispiel: 🎜rrreee

    Das obige ist der detaillierte Inhalt vonSo implementieren Sie Thread-Sicherheit in der gleichzeitigen Java-Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen
    Vorheriger Artikel:Was sind Java-Pseudo-Generika?Nächster Artikel:Was sind Java-Pseudo-Generika?