class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
Kann jemand erklären, warum die obige Klasse nicht threadsicher ist?
java
multithreading
thread-safety
das kinder
quelle
quelle
increment
) benötigt, ist sie möglicherweise threadsicher. Oder wenn Sie ein Sperrobjekt verwendet haben. Wie gesagt, ich weiß nichts über Java - mein Kommentar stammt aus C # -Wissen.synchronized
sollte die nur in statischen Methoden verwendet werden. Selbst wenn Sie dieincrement
Methode entfernen , ist sie meiner Meinung nach immer noch nicht threadsicher, da zwei Instanzen (die nur über dieselbe Instanz synchronisierten Zugriff haben) die Methode gleichzeitig aufrufen können.Antworten:
Da die
increment
Methode iststatic
, wird sie auf dem Klassenobjekt für die synchronisiertThreadSafeClass
. Diedecrement
Methode ist nicht statisch und wird auf der zum Aufrufen verwendeten Instanz synchronisiert. Das heißt, sie werden auf verschiedenen Objekten synchronisiert und somit können zwei verschiedene Threads die Methoden gleichzeitig ausführen. Da die Operationen++
und--
nicht atomar sind, ist die Klasse nicht threadsicher.Da dies auch der Fall
count
iststatic
, ist das Änderndecrement
einer synchronisierten Instanzmethode unsicher, da sie auf verschiedenen Instanzen aufgerufen undcount
gleichzeitig auf diese Weise geändert werden kann.quelle
count
es falsch iststatic
, eine Instanzmethode zudecrement()
haben, selbst wenn es keinestatic
increment()
Methode gab, da zwei Threadsdecrement()
auf verschiedenen Instanzen aufrufen können, um denselben Zähler gleichzeitig zu ändern.synchronized
Blöcke im Allgemeinen (auch für den gesamten Methodeninhalt) zu verwenden, anstatt den Modifikator für die Methode zu verwenden, dhsynchronized(this) { ... }
undsynchronized(ThreadSafeClass.class) { ... }
.++
und--
sind nicht atomar, auch nicht aufvolatile int
.Synchronized
kümmert sich um das Lese- / Aktualisierungs- / Schreibproblem mit++
/--
, aber dasstatic
Schlüsselwort ist hier der Schlüssel . Gute Antwort!synchronized
Instanzmethode aus ist von Natur aus falsch . Erwarten Sie nur nicht, dass "synchronisiert" auf der Instanzmethode Schutz für die statischen Daten bietet. Das einzige Problem hierbei ist das, was Sie in Ihrem ersten Absatz gesagt haben: Die Methoden verwenden unterschiedliche Sperren, um dieselben Daten zu schützen, und das bietet natürlich überhaupt keinen Schutz.Sie haben zwei synchronisierte Methoden, aber eine davon ist statisch und die andere nicht. Beim Zugriff auf eine synchronisierte Methode wird je nach Typ (statisch oder nicht statisch) ein anderes Objekt gesperrt. Bei einer statischen Methode wird das Class-Objekt gesperrt, während bei dem nicht statischen Block die Instanz der Klasse, die die Methode ausführt, gesperrt wird. Da Sie zwei verschiedene gesperrte Objekte haben, können Sie zwei Threads haben, die dasselbe Objekt gleichzeitig ändern.
quelle
increment
Da es statisch ist, wird die Synchronisation für die Klasse selbst durchgeführt.decrement
Da die Objektinstanziierung nicht statisch ist, wird die Synchronisierung durchgeführt, dies sichert jedoch nichts wiecount
die statische.Ich möchte das hinzufügen, um einen thread-sicheren Zähler zu deklarieren. Ich glaube, der einfachste Weg ist,
AtomicInteger
anstelle eines primitiven int zu verwenden.Lassen Sie sich von mir zu den
java.util.concurrent.atomic
Paketinformationen weiterleiten.quelle
Die Antworten anderer sind ziemlich gut, erklärte der Grund. Ich füge nur etwas hinzu, um es zusammenzufassen
synchronized
:synchronized
onfun1
undfun2
wird auf Instanzobjektebene synchronisiert.synchronized
onfun4
wird auf Klassenobjektebene synchronisiert. Was bedeutet:a1.fun1()
gleichzeitig anrufen, wird der letztere Anruf blockiert.a1.fun1()
und Thread 2a1.fun2()
gleichzeitig aufrufen, wird der letztere Anruf blockiert.a1.fun1()
und Thread 2 gleichzeitig aufrufena1.fun3()
, ohne zu blockieren, werden die beiden Methoden gleichzeitig ausgeführt.A.fun4()
, wenn andere Threads aufrufenA.fun4()
oderA.fun5()
gleichzeitig, werden letztere Aufrufe blockiert, dasynchronized
on auffun4
Klassenebene ist.A.fun4()
, Thread 2a1.fun1()
gleichzeitig aufruft, keine Blockierung, werden die beiden Methoden gleichzeitig ausgeführt.quelle
decrement
ist auf eine andere Sache zu sperren,increment
damit sie sich nicht gegenseitig am Laufen hindern.decrement
einer Instanz sperrt eine andere Sache als das Aufrufen einerdecrement
anderen Instanz, wirkt sich jedoch auf dasselbe aus.Das erste bedeutet, dass überlappende Anrufe zu
increment
unddecrement
zu einer Löschung (korrekt), einem Inkrement oder einem Dekrement führen können.Das zweite bedeutet, dass zwei überlappende Aufrufe
decrement
auf verschiedenen Instanzen zu einer doppelten Dekrementierung (korrekt) oder einer einzelnen Dekrementierung führen können.quelle
Da zwei verschiedene Methoden eine Instanzebene und eine Klassenebene sind, müssen Sie zwei verschiedene Objekte sperren, um ThreadSafe zu erstellen
quelle
Wie in anderen Antworten erläutert, ist Ihr Code nicht threadsicher, da die statische Methode den
increment()
Klassenmonitor und die nicht statische Methode dendecrement()
Objektmonitor sperrt.Für dieses Codebeispiel gibt es eine bessere Lösung ohne
synchronzed
Verwendung von Schlüsselwörtern. Sie müssen AtomicInteger verwenden , um die Thread-Sicherheit zu erreichen.Thread sicher mit
AtomicInteger
:quelle