Kopieren Sie den Codecode wie folgt:
öffentlicher synchronisierter void run()
{
}
Wie aus dem obigen Code ersichtlich ist, kann die Ausführungsmethode synchronisiert werden, solange das Schlüsselwort „synced“ zwischen void und public hinzugefügt wird. Das heißt, für die Objektinstanz derselben Java-Klasse kann nur die Ausführungsmethode synchronisiert werden Wird von einem Thread gleichzeitig aufgerufen und kann von anderen Threads erst aufgerufen werden, nachdem der aktuelle Lauf ausgeführt wurde. Selbst wenn der aktuelle Thread die Yield-Methode in der Run-Methode ausführt, wird er nur für eine Weile angehalten. Da andere Threads die Ausführungsmethode nicht ausführen können, wird der aktuelle Thread schließlich mit der Ausführung fortfahren. Schauen Sie sich zunächst den folgenden Code an:
Das Schlüsselwort synchronisiert ist nur an eine Objektinstanz gebunden
Kopieren Sie den Codecode wie folgt:
Klassentest
{
öffentliche synchronisierte Void-Methode()
{
}
}
Die öffentliche Klasse Sync implementiert Runnable
{
privater Testtest;
public void run()
{
test.method();
}
öffentliche Synchronisierung (Testtest)
{
this.test = test;
}
public static void main(String[] args) löst eine Ausnahme aus
{
Test test1 = neuer Test();
Test test2 = neuer Test();
Sync sync1 = new Sync(test1);
Sync sync2 = new Sync(test2);
neuer Thread(sync1).start();
neuer Thread(sync2).start();
}
}
Die Methodenmethoden in der Testklasse sind synchron. Der obige Code erstellt jedoch zwei Instanzen der Testklasse, sodass die Methodenmethoden von test1 und test2 separat ausgeführt werden. Um die Methoden zu synchronisieren, müssen Sie beim Erstellen einer Instanz der Sync-Klasse eine Instanz derselben Testklasse an ihren Konstruktor übergeben, wie im folgenden Code gezeigt:
Sync sync1 = new Sync(test1);
Sie können synchronisiert nicht nur verwenden, um nicht statische Methoden zu synchronisieren, sondern auch synchronisiert, um statische Methoden zu synchronisieren. Beispielsweise kann die Methode method wie folgt definiert werden:
Kopieren Sie den Codecode wie folgt:
Klassentest
{
öffentliche statische synchronisierte void-Methode() { }
}
Erstellen Sie wie folgt eine Objektinstanz der Testklasse:
Test test = neuer Test();
Bei statischen Methoden ist die Methode synchronisiert, unabhängig davon, ob Sie test.method() oder Test.method() zum Aufrufen der Methode verwenden Instanzen nicht statischer Methoden.
Unter den 23 Entwurfsmustern ist der Singleton-Modus auch Thread-unsicher, wenn er nach herkömmlichen Methoden entworfen wird. Der folgende Code ist ein Thread-unsicherer Singleton-Modus.
Kopieren Sie den Codecode wie folgt:
Pakettest;
// Thread-sicherer Singleton-Modus
Klasse Singleton
{
privates statisches Singleton-Beispiel;
privater Singleton()
{
}
öffentliches statisches Singleton getInstance()
{
if (Beispiel == null)
{
Thread.yield(); // Um die Thread-Unsicherheit des Singleton-Modus zu verstärken
probe = new Singleton();
}
Probe zurücksenden;
}
}
Die öffentliche Klasse MyThread erweitert Thread
{
public void run()
{
Singleton singleton = Singleton.getInstance();
System.out.println(singleton.hashCode());
}
public static void main(String[] args)
{
Thread-Threads[] = neuer Thread[5];
for (int i = 0; i < threads.length; i++)
threads[i] = new MyThread();
for (int i = 0; i < threads.length; i++)
threads[i].start();
}
}
Die Yield-Methode wird im obigen Code aufgerufen, um die Thread-Unsicherheit des Singleton-Modus anzuzeigen. Wenn diese Zeile entfernt wird, ist die obige Implementierung immer noch Thread-unsicher, aber die Wahrscheinlichkeit eines Auftretens ist viel geringer.
Die Ergebnisse der Ausführung des Programms sind wie folgt:
Kopieren Sie den Codecode wie folgt:
25358555
26399554
7051261
29855319
5383406
Die oben genannten Laufergebnisse können in verschiedenen Laufumgebungen unterschiedlich sein, aber im Allgemeinen sind die fünf Ausgabezeilen nicht genau gleich. Wie aus dieser Ausgabe hervorgeht, gibt es fünf Objektinstanzen, die über die getInstance-Methode abgerufen werden, und nicht nur eine, wie wir erwartet hatten. Dies liegt daran, dass ein Thread, wenn er Thread.yield() ausführt, die CPU-Ressourcen an einen anderen Thread übergibt. Da die Anweisung zum Erstellen einer Singleton-Objektinstanz beim Wechseln zwischen Threads nicht ausgeführt wird, bestehen alle diese Threads die if-Beurteilung, sodass fünf Objektinstanzen erstellt werden (vier oder drei Objektinstanzen, je nachdem, wie viele Threads durchlaufen werden). Die if-Beurteilung vor dem Erstellen des Singleton-Objekts kann dazu führen, dass das Ergebnis bei jeder Ausführung unterschiedlich ist.
Um den oben genannten Singleton-Modus threadsicher zu machen, fügen Sie einfach das synchronisierte Schlüsselwort zu getInstance hinzu. Der Code lautet wie folgt:
öffentlicher statischer synchronisierter Singleton getInstance() { }
Natürlich gibt es eine einfachere Möglichkeit, nämlich beim Definieren der Singleton-Variablen ein Singleton-Objekt zu erstellen. Der Code lautet wie folgt:
private static final Singleton sample = new Singleton();
Dann geben Sie das Beispiel einfach direkt in der getInstance-Methode zurück. Obwohl diese Methode einfach ist, ist sie beim Erstellen eines Singleton-Objekts in der getInstance-Methode nicht flexibel. Leser können verschiedene Methoden verwenden, um das Singleton-Muster je nach spezifischen Anforderungen zu implementieren.
Bei der Verwendung des synchronisierten Schlüsselworts sind vier Punkte zu beachten:
1. Das synchronisierte Schlüsselwort kann nicht vererbt werden.
Sie können synchronisiert zwar zum Definieren von Methoden verwenden, synchronisiert ist jedoch nicht Teil der Methodendefinition, sodass das synchronisierte Schlüsselwort nicht vererbt werden kann. Wenn eine Methode in der übergeordneten Klasse das synchronisierte Schlüsselwort verwendet und diese Methode in der untergeordneten Klasse überschreibt, ist die Methode in der untergeordneten Klasse standardmäßig nicht synchronisiert und muss in der untergeordneten Klasse explizit angegeben werden. Fügen Sie einfach das synchronisierte Schlüsselwort zur Methode hinzu. Natürlich können Sie auch die entsprechende Methode in der übergeordneten Klasse in der Methode der Unterklasse aufrufen. Auf diese Weise ruft die Unterklasse die Methode der übergeordneten Klasse auf Unterklasse entspricht der Synchronisation. Beispielcodes für diese beiden Methoden lauten wie folgt:
Fügen Sie das synchronisierte Schlüsselwort zur Unterklassenmethode hinzu
Kopieren Sie den Codecode wie folgt:
Klasse Eltern
{
öffentliche synchronisierte void-Methode() { }
}
Klasse Child erweitert Parent
{
öffentliche synchronisierte void-Methode() { }
}
Rufen Sie die synchronisierte Methode der übergeordneten Klasse in der Unterklassenmethode auf
Kopieren Sie den Codecode wie folgt:
Klasse Eltern
{
öffentliche synchronisierte void-Methode() { }
}
Klasse Child erweitert Parent
{
public void method() { super.method( }
}
2. Das synchronisierte Schlüsselwort kann beim Definieren von Schnittstellenmethoden nicht verwendet werden.
3. Der Konstruktor kann das synchronisierte Schlüsselwort nicht verwenden, kann jedoch den synchronisierten Block verwenden, der im nächsten Abschnitt zur Synchronisierung erläutert wird.
4. Synchronisiert kann frei platziert werden.
In den vorherigen Beispielen wird das synchronisierte Schlüsselwort vor dem Rückgabetyp der Methode platziert. Dies ist jedoch nicht der einzige Ort, an dem synchronisiert werden kann. Bei nicht statischen Methoden kann synchronisiert auch vor der Methodendefinition platziert werden. Bei statischen Methoden kann synchronisiert vor statisch stehen.
Kopieren Sie den Codecode wie folgt:
öffentliche synchronisierte Void-Methode();
synchronisierte öffentliche Void-Methode();
öffentliche statische synchronisierte void-Methode();
öffentliche synchronisierte statische Void-Methode();
synchronisierte öffentliche statische Void-Methode();
Bitte beachten Sie jedoch, dass synchronisiert nicht nach dem Methodenrückgabetyp platziert werden kann. Der folgende Code ist beispielsweise falsch:
Kopieren Sie den Codecode wie folgt:
public void synchronisierte Methode();
öffentliche statische Void-synchronisierte Methode();
Das synchronisierte Schlüsselwort kann nur zum Synchronisieren von Methoden und nicht von Klassenvariablen verwendet werden. Der folgende Code ist ebenfalls falsch.
Kopieren Sie den Codecode wie folgt:
öffentlich synchronisiert int n = 0;
öffentliches statisches synchronisiertes int n = 0;
Obwohl die Verwendung der synchronisierten Schlüsselwort-Synchronisierungsmethode die sicherste Synchronisierungsmethode ist, führt die übermäßige Verwendung des synchronisierten Schlüsselworts zu unnötigem Ressourcenverbrauch und Leistungsverlust. Obwohl es oberflächlich betrachtet den Anschein hat, dass synchronisiert eine Methode sperrt, sperrt synchronisiert tatsächlich eine Klasse. Mit anderen Worten: Wenn synchronisiert beim Definieren der beiden nicht statischen Methoden Methode1 und Methode2 verwendet wird, kann Methode2 nicht ausgeführt werden, bevor Methode1 ausgeführt wird. Ähnlich verhält es sich bei statischen und nichtstatischen Methoden. Statische und nicht statische Methoden beeinflussen sich jedoch nicht gegenseitig. Schauen Sie sich den folgenden Code an:
Kopieren Sie den Codecode wie folgt:
Pakettest;
Die öffentliche Klasse MyThread1 erweitert Thread
{
public String methodName;
öffentliche statische Void-Methode (String s)
{
System.out.println(s);
while(true)
}
öffentliche synchronisierte void-Methode1()
{
method("nichtstatische Methode1 Methode");
}
öffentliche synchronisierte void-Methode2()
{
method("nichtstatische Methode2-Methode");
}
öffentliche statische synchronisierte void-Methode3()
{
method("statische Methode3 Methode");
}
öffentliche statische synchronisierte void-Methode4()
{
method("statische Methode4 Methode");
}
public void run()
{
versuchen
{
getClass().getMethod(methodName).invoke(this);
}
Catch (Ausnahme e)
{
}
}
public static void main(String[] args) löst eine Ausnahme aus
{
MyThread1 myThread1 = new MyThread1();
for (int i = 1; i <= 4; i++)
{
myThread1.methodName = "method" + String.valueOf(i);
neuer Thread(myThread1).start();
Schlaf(100);
}
}
}
Die Laufergebnisse sind wie folgt:
Kopieren Sie den Codecode wie folgt:
Nicht statische Methode1 Methode
Statische Methode3-Methode
Wie aus den obigen Ausführungsergebnissen ersichtlich ist, können Methode2 und Methode4 erst ausgeführt werden, wenn Methode1 und Methode3 abgeschlossen sind. Daher können wir den Schluss ziehen, dass die Verwendung des synchronisierten Schlüsselworts zum Definieren einer nicht statischen Methode in einer Klasse Auswirkungen auf alle nicht statischen Methoden hat, die mit dem synchronisierten Schlüsselwort in dieser Klasse definiert werden. Wenn eine statische Methode definiert ist, wirkt sich dies auf alle statischen Methoden aus, die mit dem synchronisierten Schlüsselwort in der Klasse definiert werden. Dies ähnelt einer Tabellensperre in einer Datentabelle. Wenn ein Datensatz geändert wird, sperrt das System die gesamte Tabelle. Daher wird die Leistung des Programms erheblich beeinträchtigt.