Heim  >  Artikel  >  Java  >  Werden Sperrcodes oder Objekte synchronisiert?

Werden Sperrcodes oder Objekte synchronisiert?

高洛峰
高洛峰Original
2016-12-13 11:10:291138Durchsuche

In Java wird das synchronisierte Schlüsselwort verwendet, um die Thread-Synchronisierung zu steuern. Dies bedeutet, dass das synchronisierte Codesegment nicht von mehreren Threads gleichzeitig in einer Multithread-Umgebung ausgeführt wird. synchronisiert kann einem Codeabschnitt oder einer Methode hinzugefügt werden.

Der Schlüssel ist: Denken Sie nicht, dass alles gut wird, wenn Sie eine Synchronisierung zu einer Methode oder einem Codesegment hinzufügen. Sehen Sie sich den folgenden Codeabschnitt an:

    public synchronized void test() {  
        System.out.println("test开始..");  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("test结束..");  
    }  
}  
  
class MyThread extends Thread {  
  
    public void run() {  
        Sync sync = new Sync();  
        sync.test();  
    }  
}  
  
public class Main {  
  
    public static void main(String[] args) {  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread();  
            thread.start();  
        }  
    }  
}

Ausführungsergebnisse: Test beginnt.. Test beginnt.. Test endet.. Test endet.. Test endet..

Es ist ersichtlich, dass das obige Programm drei Threads startet und die test()-Methode ausführt Die Methode test() fügt zwar die Synchronisierung hinzu, läuft aber gleichzeitig. Es scheint, dass die Synchronisierung keine Wirkung hat.

Entfernen Sie synchronisiert aus der test()-Methode und fügen Sie synchronisiert(this) in die Methode ein:

public void test() {  
    synchronized(this){  
        System.out.println("test开始..");  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
        System.out.println("test结束..");  
    }  
}

Laufergebnis: Test startet.. Test startet.. Test startet.. Die Der Test ist vorbei. Der Test ist vorbei. Der Test ist vorbei.

Alles ist immer noch so ruhig und die Synchronisierung hat keine Wirkung.

Tatsächlich können synchronisierte (diese) und nicht statische synchronisierte Methoden (wie bei der statischen synchronisierten Methode siehe unten) nur verhindern, dass mehrere Threads das Synchronisationscodesegment desselben Objekts gleichzeitig ausführen Zeit.

Zurück zum Titel dieses Artikels: Synchronisiert Sperrcode oder Objekte. Die Antwort lautet: synchronisiert sperrt das Objekt in den Klammern, nicht den Code. Bei nicht statischen synchronisierten Methoden ist das Objekt selbst gesperrt, nämlich dieses.

Wenn die Synchronisierung ein Objekt sperrt und andere Threads ebenfalls die Sperre des Objekts erhalten möchten, müssen sie warten, bis der Thread die Ausführung abgeschlossen hat, und die Sperre aufheben, bevor sie das Objekt erneut sperren, um den Thread zu erreichen Synchronisation. Selbst wenn zwei verschiedene Codesegmente dasselbe Objekt sperren müssen, können die beiden Codesegmente in einer Multithread-Umgebung nicht gleichzeitig ausgeführt werden.

Wenn wir also das synchronisierte Schlüsselwort verwenden, sollten wir den Umfang des Codesegments so weit wie möglich einschränken. Wenn wir dem Codesegment eine Synchronisierung hinzufügen können, sollten wir nicht der gesamten Methode eine Synchronisierung hinzufügen. Dies wird als Reduzierung der Granularität der Sperre und gleichzeitigere Gestaltung des Codes bezeichnet. Der Grund liegt in der obigen Überlegung: Das Sperrcodesegment ist zu lang, andere Threads müssen lange warten und die Blumen des Wartens werden verblassen. Natürlich ist dieser Absatz ein Exkurs und hat wenig mit der Kernidee dieses Artikels zu tun.

Wenn Sie sich den obigen Code ansehen, verfügt jeder Thread über ein neues Sync-Klassenobjekt, was bedeutet, dass drei Sync-Objekte generiert werden. Da es sich nicht um dasselbe Objekt handelt, können mehrere Threads gleichzeitig synchronisierte Methoden oder Codes ausführen. Teil.

Um den oben genannten Standpunkt zu überprüfen, ändern Sie den Code so, dass drei Threads dasselbe Sync-Objekt verwenden.

class MyThread extends Thread {  
  
    private Sync sync;  
  
    public MyThread(Sync sync) {  
        this.sync = sync;  
    }  
  
    public void run() {  
        sync.test();  
    }  
}  
  
public class Main {  
  
    public static void main(String[] args) {  
        Sync sync = new Sync();  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread(sync);  
            thread.start();  
        }  
    }  
}

Laufendes Ergebnis: Test beginnt.. Test endet.. Test beginnt.. Test endet.. Test beginnt.. Test endet..

Sie können sehen, dass dies zu diesem Zeitpunkt synchronisiert ist Es hat funktioniert.

Was sollten Sie also tun, wenn Sie diesen Code wirklich sperren möchten? Das heißt, wenn es sich immer noch um den ursprünglichen Code handelt und jeder Thread ein neues Sync-Objekt erstellt, wie können wir dann verhindern, dass die Testmethode von mehreren Threads ausgeführt wird?

Die Lösung ist auch sehr einfach: Sperren Sie einfach dasselbe Objekt. Beispielsweise ist es in Ordnung, dasselbe feste Objekt nach der Synchronisierung in Klammern zu sperren. Dies ist kein Problem, aber der üblichere Ansatz besteht darin, das dieser Klasse entsprechende Klassenobjekt durch synchronisierte Sperren zuzulassen.

class Sync {  
  
    public void test() {  
        synchronized (Sync.class) {  
            System.out.println("test开始..");  
            try {  
                Thread.sleep(1000);  
            } catch (InterruptedException e) {  
                e.printStackTrace();  
            }  
            System.out.println("test结束..");  
        }  
    }  
}  
  
class MyThread extends Thread {  
  
    public void run() {  
        Sync sync = new Sync();  
        sync.test();  
    }  
}  
  
public class Main {  
  
    public static void main(String[] args) {  
        for (int i = 0; i < 3; i++) {  
            Thread thread = new MyThread();  
            thread.start();  
        }  
    }  
}

Laufendes Ergebnis: Test beginnt.. Test endet.. Test beginnt.. Test endet.. Test beginnt.. Test endet..

Der obige Code verwendet synchronisiert(Sync. Klasse) erzielt den Effekt einer globalen Sperre.

Statische synchronisierte Methode kann nicht durch Hinzufügen des Klassennamens und des Methodennamens aufgerufen werden, sodass diese nicht gesperrt wird, sondern das Klassenobjekt der Klasse , Die statische synchronisierte Methode entspricht auch der globalen Eine Sperre entspricht dem Sperren eines Codesegments.


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