Verwenden Sie `synced()` und `withLock()`, um gemeinsam genutzte Ressourcen in Kotlin zu sperren
- Generieren Sie ein Kotlin-Projekt
- Thread-Interferenz in Aktion
-
Sperren Sie gemeinsam genutzte Ressourcen mit der Funktion
synchronized()
in Kotlin -
Sperren Sie gemeinsam genutzte Ressourcen mit der Funktion
withLock()
in Kotlin - Abschluss
Bei der Arbeit mit Multithread-Anwendungen müssen wir sicherstellen, dass der Zugriff auf gemeinsam genutzte Ressourcen verwaltet wird, um inkonsistente Daten zu vermeiden. Synchronisierung ist der Ansatz, den wir normalerweise verwenden, wenn wir den Zugriff auf gemeinsam genutzte Ressourcen in unseren Anwendungen steuern möchten.
Die Synchronisierung wird mithilfe von Sperren realisiert, wodurch sichergestellt wird, dass kein Thread auf die gemeinsam genutzte Ressource zugreift, bis der aktuell ausgeführte Thread seine Ausführung beendet hat. Ein Thread muss zuerst die Sperre eines Objekts erhalten, bevor er auf die gemeinsam genutzte Ressource zugreift, und sie nach Abschluss freigeben.
Es gibt verschiedene Möglichkeiten, Sperren zu erstellen, und in diesem Tutorial lernen wir, wie Sperren in Kotlin erstellt werden, um den Zugriff auf freigegebene Ressourcen zu kontrollieren.
Generieren Sie ein Kotlin-Projekt
Öffnen Sie die IntelliJ-Entwicklungsumgebung und wählen Sie Datei > Neu > Projekt
. Geben Sie im sich öffnenden Fenster den Projektnamen als kotlin-withlock
ein, wählen Sie Kotlin
im Abschnitt Sprache und wählen Sie Intellij
als Build System. Drücken Sie abschließend die Schaltfläche Erstellen
, um das Projekt zu generieren.
Nachdem die Anwendung generiert wurde, erstellen Sie eine Datei mit dem Namen Main.kt
im Ordner src/main/kotlin
. Wir werden diese Datei verwenden, um alle Codebeispiele für dieses Tutorial zu implementieren.
Thread-Interferenz in Aktion
Thread-Interferenzen treten in einer Multithread-Anwendung ohne Kontrolle darüber auf, wie auf gemeinsam genutzte Ressourcen zugegriffen wird. Der folgende Code zeigt, wie die Thread-Interferenz in einer Multithread-Anwendung auftritt.
Kopieren Sie den folgenden Code und fügen Sie ihn in die Datei Main.kt
ein.
class Calculator {
fun addIntArray() {
var initialValue = 0;
for (number in 1..5) {
println(
Thread.currentThread().name
+ " ---> " + initialValue + " + "
+ number + " = "
.plus(String.format("%d", (initialValue + number)))
);
initialValue += number;
Thread.sleep(500);
}
}
}
fun main() {
val calculator = Calculator();
Thread {
calculator.addIntArray();
}.start();
Thread {
calculator.addIntArray();
}.start();
}
In diesem Code haben wir eine Methode namens addIntArray()
innerhalb einer Klasse namens Calculator
erstellt. Diese Methode ist eine gemeinsam genutzte Ressource in unserem Code, und da wir mehrere Threads erstellen werden, haben wir eine println()
-Methode hinzugefügt, die es uns ermöglicht, den aktuell ausgeführten Thread in der Konsole zu protokollieren.
Wenn die sleep()
-Methode aufgerufen wird, wird der aktuell ausgeführte Thread für 500 Millisekunden angehalten und ein anderer Thread beginnt zu laufen. Das bedeutet, dass die Threads gleichzeitig auf unsere Methode zugreifen, was zu Dateninkonsistenzen führen kann.
In der Methode main()
haben wir zwei Threads erstellt und die Methode start()
für sie aufgerufen, um mit der Ausführung der Methode addIntArray()
des von uns erstellten Rechnerobjekts zu beginnen.
Führen Sie diesen Code aus und beachten Sie, wie die Threads verschachtelt sind, wie unten gezeigt.
Thread-0 ---> 0 + 1 = 1
Thread-1 ---> 0 + 1 = 1
Thread-0 ---> 1 + 2 = 3
Thread-1 ---> 1 + 2 = 3
Thread-1 ---> 3 + 3 = 6
Thread-0 ---> 3 + 3 = 6
Thread-1 ---> 6 + 4 = 10
Thread-0 ---> 6 + 4 = 10
Thread-0 ---> 10 + 5 = 15
Thread-1 ---> 10 + 5 = 15
Sperren Sie gemeinsam genutzte Ressourcen mit der Funktion synchronized()
in Kotlin
Dieses Beispiel verwendet die Methode addIntArray()
, die wir im vorherigen Abschnitt implementiert haben, um zu zeigen, wie der Zugriff darauf verwaltet wird. Kommentieren Sie die im vorherigen Beispiel erstellte Methode main()
aus und kopieren Sie den folgenden Code und fügen Sie ihn nach dem Kommentar in die Datei Main.kt
ein.
val calculator = Calculator();
fun sumUsingSynchronization(): Unit = synchronized(calculator) {
calculator.addIntArray();
}
fun main() {
Thread {
sumUsingSynchronization();
}.start();
Thread {
sumUsingSynchronization()
}.start();
}
Das Hauptziel dieses Lernprogramms besteht darin, zu lernen, wie Sperren erstellt werden, um den exklusiven Zugriff von Threads auf eine gemeinsam genutzte Ressource sicherzustellen. Standardmäßig haben Objekte implizite Monitorsperren, die Threads verwenden, um eine Synchronisation zu erreichen, und dieser Code verwendet eine implizite Monitorsperre, indem er das Calculator
-Objekt an die synchronized()
-Funktion übergibt.
Die Funktion synchronized()
wird von der Funktion sumUsingSynchronization()
aufgerufen, die wiederum die Methode addIntArray()
aufruft. In der Methode main()
haben wir zwei Threads erstellt und die Methode start()
für sie aufgerufen, um die Ausführung zu starten.
Beachten Sie, dass es keine Interferenz zwischen den beiden Threads gibt, da unser Code eine implizite Monitorsperre verwendet. Der erste Thread verwendet ausschließlich die Methode addIntArray()
, bis er seine Ausführung beendet hat, bevor der zweite Thread startet.
Die Funktion synchronized()
ist nicht nur auf die impliziten Monitorsperren beschränkt, sondern kann auch beliebige andere Sperren wie die ReentrantLock verwenden, und wir müssen nur die Sperre als Argument dieser Methode übergeben. Führen Sie diesen Code aus und stellen Sie sicher, dass die Ausgabe wie unten gezeigt ist.
Thread-0 ---> 0 + 1 = 1
Thread-0 ---> 1 + 2 = 3
Thread-0 ---> 3 + 3 = 6
Thread-0 ---> 6 + 4 = 10
Thread-0 ---> 10 + 5 = 15
Thread-1 ---> 0 + 1 = 1
Thread-1 ---> 1 + 2 = 3
Thread-1 ---> 3 + 3 = 6
Thread-1 ---> 6 + 4 = 10
Thread-1 ---> 10 + 5 = 15
Sperren Sie gemeinsam genutzte Ressourcen mit der Funktion withLock()
in Kotlin
Kommentieren Sie die im vorherigen Beispiel erstellte Methode main()
aus und kopieren Sie den folgenden Code und fügen Sie ihn nach dem Kommentar in die Datei Main.kt
ein.
import java.util.concurrent.locks.Lock
import java.util.concurrent.locks.ReentrantLock
import kotlin.concurrent.withLock
val reentrantLock: Lock = ReentrantLock();
fun sumUsingLock(): Unit = reentrantLock.withLock {
calculator.addIntArray();
}
fun main() {
Thread {
sumUsingLock();
}.start();
Thread {
sumUsingLock()
}.start();
}
In diesem Code haben wir eine Methode namens sumUsingLock()
erstellt, die der Erweiterungsfunktion withLock()
der Schnittstelle Lock
zugewiesen ist. Die Erweiterungsfunktion withLock()
verwendet die bereitgestellte Lock-Implementierung, um den Codeblock exklusiv für jeden der mehreren erstellten Threads auszuführen.
In diesem Beispiel haben wir mit ReentrantLock
eine benutzerdefinierte Sperre erstellt, die die Lock
-Schnittstelle implementiert. Diese Sperre wird von den Threads verwendet, die erstellt wurden, um ausschließlich die Methode addIntArray()
auszuführen.
Führen Sie diesen Code aus und stellen Sie sicher, dass die Ausgabe wie unten gezeigt ist.
Thread-0 ---> 0 + 1 = 1
Thread-0 ---> 1 + 2 = 3
Thread-0 ---> 3 + 3 = 6
Thread-0 ---> 6 + 4 = 10
Thread-0 ---> 10 + 5 = 15
Thread-1 ---> 0 + 1 = 1
Thread-1 ---> 1 + 2 = 3
Thread-1 ---> 3 + 3 = 6
Thread-1 ---> 6 + 4 = 10
Thread-1 ---> 10 + 5 = 15
Abschluss
In diesem Lernprogramm haben wir gelernt, wie Sie den Zugriff auf gemeinsam genutzte Ressourcen verwalten, indem wir behandelt haben, wie Sperren für diese Ressourcen erstellt werden. Wir haben behandelt, wie Interferenzen auftreten, wie Sperren mit der Funktion synchronized()
verwendet werden und wie Sperren mit der Funktion withLock()
verwendet werden.
Beachten Sie, dass der Unterschied zwischen diesen beiden Ansätzen darin besteht, dass die Funktion synchronized()
nicht auf eine Sperrimplementierung beschränkt ist, die Funktion withLock()
jedoch auf die Implementierung Lock
.
David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.
LinkedIn GitHub