Wie man Methoden synchronisieren, wenn Java-Threads

Jedes Mal, wenn Sie auf einem Java-Programm arbeiten, das Threads verwendet, haben Sie die fiese Frage der Gleichzeitigkeit zu berücksichtigen. Insbesondere was ist, wenn zwei Threads versuchen, gleichzeitig an genau eine Methode eines Objekts zugreifen? Es sei denn, Sie sorgfältig programmieren, kann das Ergebnis katastrophal sein. Ein Verfahren, das eine einfache Berechnung durchführt liefert ungenaue Ergebnisse.

In einer Online-Banking-Anwendung, können Sie feststellen, dass einige Einlagen zweimal gutgeschrieben werden und einige Auszahlungen werden überhaupt nicht angerechnet. In einem Online-Bestellsystem, könnte man Bestellung des Kunden in einem anderen Konto des Kunden aufgezeichnet bekommen.

Der Schlüssel zu Concurrency Probleme Handhabung ist es, Methoden zu erkennen, die Daten aktualisieren und das könnte von mehr als einem Thread aufgerufen werden. Nachdem Sie diese Methoden zu identifizieren, ist die Lösung einfach. Sie fügen Sie einfach die synchronisiert Stichwort in die Methodendeklaration, wie folgt aus:

public synchronized void somemethod () ...

Dieser Code weist Java eine zu platzieren sperren auf das Objekt, so dass keine anderen Methoden können für das Objekt alle anderen synchronisierten Methoden aufrufen, bis diese Methode beendet. Mit anderen Worten, es sperrt vorübergehend multithreading für das Objekt.

Hier sind einige konkrete Beispiele. Dieser Code erstellt eine Instanz der CountDownClock Klasse.

Import java.util.concurrent.ScheduledThreadPoolExecutor-public class DoTwoThings {ScheduledThreadPoolExecutor Pool = new ScheduledThreadPoolExecutor (2) -CountDownClock Uhr = new CountDownClock (20) -public static void main (String [] args) {new DoTwoThings () -} DoTwoThings ( ) {pool.execute (Uhr) -pool.execute (Uhr) -pool.shutdown () -}}

Die resultierende Ausgabe ist ein unberechenbarer Mischmasch aus zwei Threads 'Ausgänge, mit einigen der Zählungen dupliziert und andere ausgelassen zusammen, wie folgt aus:

T minus 20T minus 20T minus 19T minus 19T minus 18T minus 17T minus 16T minus 15T minus 13T minus 13T minus 12T minus 12T minus 11T minus 11T minus 10T minus 9T minus 7T minus 7T minus 6T minus 5T minus 4T minus 3T minus 2T minus 2T minus 1T minus 0

Die beiden Threads ausführen ihre Schleifen gleichzeitig, so dass nach einem Thread zeigt seine T minus 20, der andere Thread zeigt seine eigene T minus 20. Das gleiche geschieht für T minus 19, T minus 18, und so weiter.

Dann erzeugt dieser Code zwei Threads, von denen jede eine Kopie der läuft CountDownClock Instanz-Code.

Import java.util.concurrent.ScheduledThreadPoolExecutor-public class DoTwoThingsSync {ScheduledThreadPoolExecutor Pool = new ScheduledThreadPoolExecutor (2) -CountDownClockSync Uhr = new CountDownClockSync (20) -public static void main (String [] args) {new DoTwoThingsSync () -} DoTwoThingsSync ( ) {pool.execute (Uhr) -pool.execute (Uhr) -pool.shutdown () -}}

Java synchronisiert Stichwort stellt sicher, dass nur ein Thread zu einem Zeitpunkt, ruft die Lauf Verfahren. Die resultierende Ausgabe zeigt eine vollständige Ausführung der Lauf Verfahren gefolgt von einem anderen.

Klasse CountDownClockSync erstreckt Thema {private int start-public CountDownClockSync (int start) {this.start = Start} synchronisiert public void run () {for (int t = Start-t> = 0- t -) {System.out- .println ( "T minus" + t) -try {Thread.sleep (1000) -} catch (InterruptedException e) {}}}}

Die beiden Themen "Anrufe an die Lauf Verfahren sind nicht verschachtelt, so dass die Ausgabe zählt von 20 nach 0 und zählt dann ein zweites Mal nach unten aus 20 nach 0:

T minus 20T minus 19T minus 18

Und so weiter, bis hin zu

T minus 2T minus 1T minus 0T minus 20T minus 19T minus 18

Und so weiter, bis hin zu

T minus 2T minus 1T minus 0

Der schwierige Teil ist, zu wissen, welche Methoden zu synchronisieren. Jede Methode, die Instanzvariablen aktualisiert ist in Gefahr - und muss synchronisiert werden. Das liegt daran, wenn zwei oder mehrere Threads, die ein Verfahren zur gleichen Zeit laufen die Fäden eine gemeinsame Kopie der Methode der Instanzvariablen haben.

Auch Methoden, die von nur einer Zeile Code bestehen, sind in Gefahr. Betrachten Sie diese Methode:

int sequenceNumber = 0-public int getNextSequenceNumber () {return sequenceNumber ++ -}

Sie würden denken, dass da diese Methode nur eine Aussage hat, ein anderer Thread es in der Mitte nicht unterbrechen konnte. Ach, das ist nicht der Fall. Diese Methode muss den Wert des bekommen Sequenznummer Feld hinzufügen 1 den aktualisierten Wert zu, speichern zurück in die Sequenznummer Feld und den Wert zurück.

In der Tat stellt diese einzelne Java-Anweisung bis 11 Bytecode-Anweisungen. Wenn der Faden zwischen einem dieser Bytecode von einem anderen Thread ruft die gleiche Methode, die Seriennummern preempted wird erhalten munged.

Aus Gründen der Sicherheit, warum machen nicht nur alle Methoden synchronisiert? Sie haben zwei Gründe, dies nicht zu tun:

  • Verfahren Synchronisierung braucht Zeit. Java hat eine Sperre für das Objekt zu erwerben, die synchronisiert werden, wobei das Verfahren auszuführen, und dann die Sperre wieder freigeben. Doch bevor es das kann, hat es zu überprüfen, um sicherzustellen, dass ein anderer Thread nicht bereits eine Sperre für das Objekt. All diese Arbeit braucht Zeit.

  • Noch wichtiger ist, besiegt den Zweck der Multithreading alle Ihre Methoden zu synchronisieren, so dass Sie nur die Methoden synchronisieren sollte, die sie benötigen.

Das synchronisiert Stichwort nicht alle Zugriff auf ein Objekt sperren. Andere Threads können noch nicht synchronisierten Methoden des Objekts ausgeführt werden, während das Objekt gesperrt ist.

Das Objekt Klasse bietet drei Methoden, die synchronisierte Objekte koordinieren ihre Aktivitäten lassen können. Das warte ab Verfahren setzt einen Thread im Wartezustand, bis ein anderer Thread ruft entweder die Objekt benachrichtigen oder (häufiger) notifyAll Verfahren. Diese Verfahren sind nützlich, wenn ein Thread hat für einen anderen Thread zu warten, etwas zu tun, bevor es weitergehen kann.

Das klassische Beispiel ist ein Bankensystem, in dem ein Thread macht Entnahmen und die andere macht Einlagen. Wenn ein Kontostand des Kunden fällt, den Faden auf Null, die Entnahmen macht anrufen warte ab- dann der Faden, der Ablagerungen macht anrufen notifyAll. Auf diese Weise jedes Mal, wenn eine Anzahlung gemacht wird, kann der Rückzug Thread den Kontostand des Kunden nochmals überprüfen, um zu sehen, ob es jetzt genug Geld hat.

Menü