Bloc synchronisé Java pour .class

Réponses:

144

L'extrait de code synchronized(X.class)utilise l'instance de classe comme moniteur. Comme il n'y a qu'une seule instance de classe (l'objet représentant les métadonnées de classe au moment de l'exécution), un thread peut être dans ce bloc.

Avec synchronized(this)le bloc est gardé par l'instance. Pour chaque instance, un seul thread peut entrer dans le bloc.

synchronized(X.class)est utilisé pour s'assurer qu'il y a exactement un thread dans le bloc. synchronized(this)garantit qu'il y a exactement un thread par instance. Si cela rend le code réel dans le bloc thread-safe dépend de l'implémentation. Si mutate, seul l'état de l'instance synchronized(this)est suffisant.

Thomas Jung
la source
6
"autant de threads peuvent entrer dans le bloc qu'il y a d'instance" implique que la seconde forme agit comme un sémaphore, ce qui n'est pas vrai. Vous devriez dire quelque chose comme: "synchronized (this) garantit qu'un seul thread peut entrer dans le bloc pour une instance donnée de la classe".
liwp
Corrigée. J'avais l'intention de dire cela.
Thomas Jung
2
quelle est l'instance de classe par rapport à l'instance?
Weishi Zeng
Donc, si vous avez une méthode statique et que nous ne voulons pas synchroniser tout son corps, alors nous synchroniser (ceci) n'est pas bon, au lieu de cela synchronisé (Foo.class) est approprié. Est-ce correct?
krupal.agile
84

Pour ajouter aux autres réponses:

static void myMethod() {
  synchronized(MyClass.class) {
    //code
  }
}

est équivalent à

static synchronized void myMethod() {
  //code
}

et

void myMethod() {
  synchronized(this) {
    //code
  }
}

est équivalent à

synchronized void myMethod() {
  //code
}
Jorn
la source
12
Il m'a fallu une deuxième lecture pour comprendre que les deux premiers exemples ont le mot-clé «statique». Il suffit de signaler cela à d'autres personnes qui ont peut-être vu cela et l'ont raté. Sans le mot-clé static, les deux premiers exemples ne seraient pas les mêmes.
kurtzbot
1
Ces exemples ne sont PAS équivalents! Les méthodes synchronisées sont «synchronisées» comme un trou lorsqu'un thread tente d'appeler les méthodes. Les blocs, d'autre part, peuvent avoir du code au-dessus et en dessous d'eux, qui peut être exécuté à partir de plusieurs threads. Ils se synchronisent uniquement dans le bloc! Ce n'est pas pareil!
JacksOnF1re
public static Singleton getInstance () {if (instance == null) {synchronized (Singleton.class) {instance = new Singleton (); }} instance de retour; }
JacksOnF1re
2
Le tout est qu'il n'y a pas de code en dehors des synchronizedblocs. Cela les rend équivalents. Si vous changez un exemple, ils ne sont en effet plus les mêmes.
Jorn
23

Non, le premier obtiendra un verrou sur la définition de classe de MyClass, pas toutes ses instances. Cependant, s'il est utilisé dans une instance, cela bloquera efficacement toutes les autres instances, car elles partagent une seule définition de classe.

Le second obtiendra un verrou sur l'instance actuelle uniquement.

Quant à savoir si cela rend vos objets thread-safe, c'est une question beaucoup plus complexe - nous aurions besoin de voir votre code!

David M
la source
1
oui, MyClass.class peut être n'importe quelle variable statique et avoir le même effet.
pstanton
0

Oui, il le fera (sur n'importe quel bloc / fonction synchronisé).

Je me posais des questions sur cette question pendant quelques jours pour moi-même (en fait à kotlin). J'ai enfin trouvé une bonne explication et je souhaite la partager:

Le verrouillage de niveau de classe empêche plusieurs threads d'entrer en bloc synchronisé dans l'une de toutes les instances disponibles de la classe au moment de l'exécution. Cela signifie que si au moment de l'exécution il y a 100 instances de DemoClass, alors un seul thread sera capable d'exécuter demoMethod () dans n'importe quelle instance à la fois, et toutes les autres instances seront verrouillées pour les autres threads.

Le verrouillage au niveau de la classe doit toujours être effectué pour sécuriser les threads de données statiques. Comme nous savons que les mots-clés statiques associent les données des méthodes au niveau de la classe, utilisez donc le verrouillage au niveau des champs ou des méthodes statiques pour le rendre au niveau de la classe.

De plus, pour savoir pourquoi .class . C'est juste parce qu'elle .classéquivaut à toute variable statique de classe similaire à:

private final static Object lock = new Object();

où le nom de la variable de verrouillage est la classe et le type est la classe <T>

En savoir plus: https://howtodoinjava.com/java/multi-threading/object-vs-class-level-locking/

vitalii
la source