Que signifie réellement le verrouillage intrinsèque pour une classe Java?


Afin de bien comprendre les problèmes et les solutions de concurrence en Java, je passais par le tutoriel Java officiel. Dans l'une des pages, ils ont défini Verrous intrinsèques et synchronisation lien . Dans cette page, ils disent que:

Tant qu'un thread possède un verrou intrinsèque, aucun autre thread ne le peut acquérir le même verrou. L'autre thread se bloquera lorsqu'il tentera de acquérir le verrou.

Aussi, ils mentionnent dans la section Verrouille Les Méthodes Synchronisées qui:

Lorsqu'un thread appelle une méthode synchronisée, il acquiert automatiquement le verrou intrinsèque pour l'objet de cette méthode et le libère lorsque le méthode retourne. Le déverrouillage du verrou se produit même si le retour a été provoqué par une exception non interceptée.

Pour moi, cela signifie qu'une fois que j'appelle une méthode synchronisée à partir de l'un des threads, j'aurai la mainmise sur le verrou intrinsèque du thread et depuis

Intrinsèque les verrous jouent un rôle dans les deux aspects de la synchronisation: imposer l'accès exclusif à l'état d'un objet et établir arrive-avant les relations qui sont essentielles à la visibilité.

Un autre thread serait-il incapable d'appeler une autre méthode synchronisée de la même classe? Si oui, alors tout le but d'avoir des méthodes synchronisées est vaincu. N'est-ce pas?

Author: Swapnil, 2016-07-06

7 answers

Donc juste pour répéter mon commentaire ci-dessus comme réponse. Le verrouillage intrinsèque signifie que vous n'avez pas besoin de créer un objet pour synchroniser vos méthodes. En comparaison, vous pouvez utiliser un verrou extrinsèque en appelant synchronized(myLock) {...}.

Ceci est un extrait du livre Java concurrency in practice :"Le fait que chaque objet ait un verrou intégré est juste une commodité afin que vous n'ayez pas besoin de créer explicitement des objets de verrouillage"

Le livre dit aussi:

Il n'y a pas inhérent relation entre le verrou intrinsèque d'un objet et son état; les champs d'un objet n'ont pas besoin d'être gardés par son intrinsèque lock, bien que ce soit une convention de verrouillage parfaitement valide qui est utilisée par de nombreuses classes. L'acquisition du verrou associé à un objet ne empêcher d'autres threads d'accéder à cet objetla seule chose qui l'acquisition d'un verrou empêche tout autre thread de faire l'acquisition de la même serrure. Le fait que chaque objet ait un verrou intégré est juste une pratique que vous n'avez pas besoin de créer explicitement des objets de verrouillage. [9] C'est à vous de construire des protocoles de verrouillage ou de synchronisation stratégies qui vous permettent d'accéder à l'état partagé en toute sécurité et de les utiliser constamment tout au long de votre programme.

Mais dans la note de bas de page, il est dit:

[9] Rétrospectivement, cette décision de conception était probablement mauvaise: non seulement cela peut être déroutant, mais cela oblige les implémenteurs de la JVM à faire compromis entre la taille de l'objet et le verrouillage performance.

Et pour répondre à vos dernières questions: vous ne pourrez pas appeler les méthodes synchronisées à partir d'un autre thread, mais vous pouvez continuer à entrer à partir du même thread (les verrous intrinsèques sont rentrants). Vous devez donc imaginer le verrouillage dans ce cas comme la sérialisation de l'accès à la méthode à partir de différents threads de l'appelant.

Si vous utilisez mal le verrouillage et que vous introduisez des risques de vie, alors oui, il est vaincu. C'est pourquoi vous devez vous assurer que vos threads concurrents sont pas à lutter les uns avec les autres trop dur.

Comme Brian Goetz place dans cette entrée de blog:

En ajustant l'utilisation de la synchronisation par une application, nous devrions essayer difficile de réduire la quantité de conflit réel, plutôt que d'essayer simplement pour éviter d'utiliser la synchronisation

 3
Author: Captain Fogetti, 2016-07-06 01:50:47

Il semble que vous ayez un malentendu (je ne sais pas si cela a causé la mauvaise conclusion) que personne n'a souligné. Quoi qu'il en soit, une brève réponse:

Verrou intrinsèque: Il suffit de penser comme, chaque objet dans JVM a en interne un verrou. synchronized mots clés essaie d'acquérir le verrou de l'objet cible. Chaque fois que vous synchronized (a) { doSomething; }, ce qui se passe réellement est

  1. la serrure dans a est acquis
  2. le code dans le bloc synchronisé est exécuté (doSomething)
  3. relâchez le verrou a

Et je souhaite que vous sachiez

public synchronized void foo() {
  doSomething;
}

Est conceptuellement le même que

public void foo() {
    synchronized(this) {
        doSomething;
    }
}

Ok, revenez à votre question, le plus gros problème, à mon humble avis, est:

Pour moi, cela signifie qu'une fois que j'appelle une méthode synchronisée à partir de l'un des threads, j'aurai le verrou intrinsèque du thread et depuis...

, Il est mal. Lorsque vous appelez une méthode synchronisée, vous êtes pas mettre la main sur le verrou du fil .

Au lieu de cela, ce threadpossédera le verrou intrinsèque de l'objet qui "possède" la méthode.

Par exemple dans thread1, vous avez appelé a.foo() et supposez que foo() est synchronisé. thread1 va acquérir le verrou intrinsèque de l'objet a se référant.

De même, si AClass.bar() est appelé (et bar est synchronisé et une méthode statique), le verrou intrinsèque de l'objet de classe AClass sera acquis.

 4
Author: Adrian Shum, 2016-07-06 03:31:55

Un verrou peut être tenu par un seul thread à la fois. Cela ne défait pas le but; que est le but.

Les threadsmut uallyex s'excluent mutuellement de l'action simultanée dans les sections critiques en acquérant un verrou, ou mutex. Cela fournit une atomicité efficace autour d'une série d'actions distinctes, de sorte que les autres threads ne voient jamais d'états intermédiaires qui pourraient violer les garanties de cohérence.

 3
Author: erickson, 2016-07-06 06:39:22

Oui, vous ne pourrez pas appeler une autre méthode synchronisée sur le même objet, à cause du verrou intrinsèque. Ce qui est au niveau de l'objet, seulement 1 thread l'acquerra.

 2
Author: Alexandru Marina, 2016-07-05 22:03:46

Peu importe que la méthode synchronized appartienne à la même classe ou non, ce qui compte, c'est que le thread appelant de la méthode acquiert le verrou ou non, si c'est le cas, il sera autorisé à entrer dans la section critique car le verrou est reentrant.

Si ce n'était pas le cas, alors un appel récursif provoquerait une impasse,

fn(){
 synchronized(mutex){ // the current thread has already acquired the mutex
   fn();
 }
}

Fn ici ne bloquera pas car le verrou est ré-entrant, c'est-à-dire ( le thread qui acquiert déjà le verrou peut entrer et louer la section critique encore tant qu'il est encore acquis).

 1
Author: Sleiman Jneidi, 2016-07-05 22:13:34

Serais-je incapable d'appeler une autre méthode synchronisée de la même classe? Si oui, alors tout le but d'avoir des méthodes synchronisées est vaincu. N'est-ce pas?

Non. Vous ne pouvez pas appeler une autre méthode synchronized sur le même objet pour le verrouillage au niveau de l'objet et vous ne pouvez pas appeler une autre méthode static sysnchronized sur la même classe.

Mais cela ne va pas à l'encontre du but d'avoir la synchronisation.

Si vous suivez l'autre page de documentation sur méthodes synchronisées:

Faire ces méthodes synchronized a deux effets:

  1. Premièrement, il n'est pas possible pour deux invocations de méthodes synchronisées sur le même objet de s'entrelacer. Lorsqu'un thread exécute une méthode synchronisée pour un objet, tous les autres threads qui invoquent des méthodes synchronisées pour le même bloc d'objet (suspendent l'exécution) jusqu'à ce que le premier thread soit terminé avec l'objet.
  2. Deuxièmement, lorsqu'une méthode synchronisée sorties, il établit automatiquement un passe-avant relation avec toute invocation ultérieure d'une méthode synchronisée pour le même objet. Cela garantit que les modifications de l'état de l'objet sont visibles par tous les threads.

Si vous autorisez deux méthodes synchronized à s'exécuter en parallèle. vous aurez forcément des erreurs d'incohérence de mémoire sur les données partagées.

Sur une note différente, Verrou fournit la meilleure alternative synchronized construire.

Question SE connexe:

La Synchronisation vs Verrouillage

 1
Author: Ravindra babu, 2017-05-23 12:00:08

Verrous peuvent être divisés en deux classes - 'réentrant" et "non réentrant'. En Java 'synchronisé', l'implémentation de base de l'interface Lock( classe ReentrantLock), interface ReadWriteLock (classe ReentrantReadWriteLock) - sont réentrantes. Réentrance signifie - un fil peut encore et encore tenir le verrou.

 0
Author: Ivan Golovach, 2016-07-06 10:14:52