Gleichzeitigkeit ist zwar nicht wirklich ein Hobby von mir, aber ich finde es interessant, und hin und wieder fasziniert es mich. In diesem Artikel geht es um Sperren, die Wahl der richtigen Art von Sperre und die Konsequenzen, wenn Sie die falsche Sperre wählen!
Im Folgenden finden Sie ein einfaches Beispielprogramm, das ein separates Lock-Objekt zum Sperren verwendet:
public class Worker {
private final Object lock = new Object();
public void work() {
synchronisiert(sperren) {
// manche Arbeit dauert lange
}
}
}
Der obige Code beschreibt einen sicheren Weg für instanzbasiertes Sperren. Natürlich können wir jede Art von Objekt zum Sperren verwenden, wir müssen nicht unbedingt Object dafür verwenden. Oder doch? Was, wenn wir zum Beispiel mit der Objektsperre nicht ganz zufrieden sind? Ich meine: Sie bietet nicht viele Informationen und ist nicht wirklich flexibel, oder? Nehmen wir an, ich möchte meiner Sperre einen Namen geben, und da ich nichts anderes als einen Namen für meine Sperre brauche, warum nicht ein einfaches String-Objekt verwenden?
public class Worker {
private final String lock = "Ein rostiges altes Schloss";
public void work() {
synchronisiert(sperren) {
println lock;
// manche Arbeit dauert lange
}
}
}
Erledigt! Wir haben jetzt eine schöne, private und endgültige (um Probleme mit der Neuordnung und Sichtbarkeit zu vermeiden) instanzbasierte String-Sperre, die immer dann ausgegeben wird, wenn wir die Methode 'work' aufrufen. Hmm, Moment mal... gab es da nicht eine Leistungsoptimierung namens String Interning? Wenn die VM unsere Anwendung ausführt, wird unser String dem String-Pool hinzugefügt. Das bedeutet, dass nur eine (1!) Instanz unserer Sperre in unserer VM vorhanden ist, anstatt eine Sperre pro Instanz. Wir sperren also nicht auf einer instanzbasierten Sperre, sondern auf Klassenebene, was zu unerwarteten Deadlocks oder Verlangsamungen in der Anwendung führen kann. Beachten Sie, dass dies seit dem Autoboxing, das in Java 5 eingeführt wurde, auch für Zahlen gilt, allerdings nicht für alle Zahlen. Das oben Gesagte gilt nur für Zahlen im Bereich [-127, 128]. Diese Zahlen werden aus einem Objektpool abgerufen und aus Leistungsgründen zwischengespeichert. Ändern wir also das obige Beispiel, um eine Zahlensperre anstelle eines Strings zu verwenden.
public class Worker {
private final Number lock = 4;
public void work() {
synchronisiert(sperren) {
println lock;
// manche Arbeit dauert lange
}
}
}
Der obige Code hat das gleiche Problem wie die String-Sperre: Statt einer instanzbasierten Sperre haben Sie eine klassenbasierte Sperre, was wahrscheinlich nicht das ist, was Sie erwartet haben!
Fazit
Kurz gesagt: Seien Sie sich der Interna der JVM bewusst. Versuchen Sie, sich der möglichen Nebeneffekte Ihres Codes bewusst zu sein, und testen Sie so viel wie möglich. Als Richtlinie würde ich vorschlagen, sich an das erste Codebeispiel zu halten: Verwenden Sie ein Objekt für Ihre Sperre, damit können Sie nichts falsch machen!
Verfasst von
Erik Pragt
Unsere Ideen
Weitere Blogs
Contact



