class ThreadSafeClass extends Thread
{
private static int count = 0;
public synchronized static void increment()
{
count++;
}
public synchronized void decrement()
{
count--;
}
}
Quelqu'un peut-il expliquer pourquoi la classe ci-dessus n'est pas thread-safe?
java
multithreading
thread-safety
das kinder
la source
la source
increment
), ce serait thread-safe. Ou si vous avez utilisé un objet de verrouillage. Comme je l'ai dit, je ne connais pas Java - mon commentaire découle de la connaissance du C #.synchronized
doit être utilisé uniquement dans les méthodes statiques. Donc, à mon avis, même si vous supprimez laincrement
méthode, ce n'est toujours pas threadsafe puisque deux instances (qui n'ont qu'un accès synchronisé via la même instance) peuvent appeler la méthode simultanément.Réponses:
Étant donné que la
increment
méthode est,static
elle se synchronisera sur l'objet de classe pour leThreadSafeClass
. Ladecrement
méthode n'est pas statique et se synchronisera sur l'instance utilisée pour l'appeler. C'est-à-dire qu'ils se synchroniseront sur des objets différents et ainsi deux threads différents pourront exécuter les méthodes en même temps. Étant donné que les opérations++
et--
ne sont pas atomiques, la classe n'est pas thread-safe.De plus, comme
count
eststatic
, en le modifiant à partir dedecrement
laquelle est synchronisée instance procédé est dangereux car il peut être demandé à différentes instances et modifier encount
même temps que de cette façon.la source
count
c'eststatic
, avoir une méthode d'instancedecrement()
est incorrect, même s'il n'y avait pas destatic
increment()
méthode, car deux threads peuvent invoquerdecrement()
sur des instances différentes modifiant le même compteur simultanément.synchronized
blocs en général (même sur tout le contenu de la méthode) au lieu d'utiliser le modificateur sur la méthode, c'estsynchronized(this) { ... }
-à- dire etsynchronized(ThreadSafeClass.class) { ... }
.++
et--
ne sont pas atomiques, même survolatile int
.Synchronized
prend en charge le problème de lecture / mise à jour / écriture avec++
/--
, mais lestatic
mot-clé est, eh bien, clé ici. Bonne réponse!synchronized
méthode d'instance non plus. Ne vous attendez pas à ce que "synchronisé" sur la méthode d'instance fournisse une protection aux données statiques. Le seul problème ici est ce que vous avez dit dans votre premier paragraphe: les méthodes utilisent des verrous différents pour tenter de protéger les mêmes données, et cela ne fournit bien sûr aucune protection.Vous avez deux méthodes synchronisées, mais l'une d'elles est statique et l'autre non. Lors de l'accès à une méthode synchronisée, en fonction de son type (statique ou non statique), un objet différent sera verrouillé. Pour une méthode statique, un verrou sera placé sur l'objet Class, tandis que pour le bloc non statique, un verrou sera placé sur l'instance de la classe qui exécute la méthode. Étant donné que vous avez deux objets verrouillés différents, vous pouvez avoir deux threads qui modifient le même objet simultanément.
la source
increment
étant statique, la synchronisation se fera sur la classe elle-même.decrement
n'étant pas statique, la synchronisation se fera sur l'instanciation de l'objet, mais cela ne sécurise rien carcount
c'est statique.J'aimerais ajouter que pour déclarer un compteur thread-safe, je pense que le moyen le plus simple est d'utiliser à la
AtomicInteger
place d'un int primitif.Laissez-moi vous rediriger vers le
java.util.concurrent.atomic
package-info.la source
Les réponses des autres sont assez bonnes expliquées la raison. J'ajoute juste quelque chose pour résumer
synchronized
:synchronized
activéfun1
etfun2
est synchronisé au niveau de l'objet d'instance.synchronized
onfun4
est synchronisé au niveau de l'objet de classe. Ce qui signifie:a1.fun1()
en même temps, ce dernier appel sera bloqué.a1.fun1()
et le fil 2 appellenta1.fun2()
en même temps, ce dernier appel sera bloqué.a1.fun1()
et le thread 2 appellea1.fun3()
en même temps, pas de blocage, les 2 méthodes seront exécutées en même temps.A.fun4()
, si d'autres threads appellentA.fun4()
ouA.fun5()
en même temps, ces derniers appels seront bloqués carsynchronized
onfun4
est au niveau de la classe.A.fun4()
, le thread 2 appellea1.fun1()
en même temps, pas de blocage, les 2 méthodes seront exécutées en même temps.la source
decrement
se verrouille sur une chose différenteincrement
pour qu'ils ne s'empêchent pas de fonctionner.decrement
sur une instance se verrouille sur une chose différente de l'appeldecrement
sur une autre instance, mais ils affectent la même chose.Le premier signifie que le chevauchement des appels à
increment
etdecrement
pourrait entraîner une annulation (correcte), un incrément ou une diminution.Le second signifie que deux appels qui se chevauchent
decrement
sur des instances différentes peuvent entraîner un double décrément (correct) ou un seul décrément.la source
Étant donné que deux méthodes différentes, l'une est au niveau de l'instance et l'autre au niveau de la classe, vous devez donc verrouiller 2 objets différents pour le rendre ThreadSafe
la source
Comme expliqué dans d'autres réponses, votre code n'est pas thread-safe car la méthode statique
increment()
verrouille le moniteur de classe et la méthode non statiquedecrement()
verrouille le moniteur d'objets.Pour cet exemple de code, une meilleure solution existe sans
synchronzed
utilisation de mot-clé. Vous devez utiliser AtomicInteger pour assurer la sécurité des threads.Thread safe en utilisant
AtomicInteger
:la source