Dans l'exemple, methodA et methodB sont des méthodes d'instance (par opposition aux méthodes statiques). Mettre synchronized
sur une méthode d'instance signifie que le thread doit acquérir le verrou (le "verrou intrinsèque") sur l'instance d'objet sur laquelle la méthode est appelée avant que le thread ne puisse commencer à exécuter le code de cette méthode.
Si vous avez deux méthodes d'instance différentes marquées comme synchronisées et que des threads différents appellent ces méthodes simultanément sur le même objet, ces threads seront en compétition pour le même verrou. Une fois qu'un thread obtient le verrou, tous les autres threads sont exclus de toutes les méthodes d'instance synchronisées sur cet objet.
Pour que les deux méthodes s'exécutent simultanément, elles devraient utiliser des verrous différents, comme ceci:
class A {
private final Object lockA = new Object();
private final Object lockB = new Object();
public void methodA() {
synchronized(lockA) {
//method A
}
}
public void methodB() {
synchronized(lockB) {
//method B
}
}
}
où la syntaxe du bloc synchronisé permet de spécifier un objet spécifique dont le thread en cours d'exécution a besoin pour acquérir le verrou intrinsèque afin d'entrer dans le bloc.
La chose importante à comprendre est que même si nous mettons un mot-clé «synchronisé» sur des méthodes individuelles, le concept de base est le verrou intrinsèque dans les coulisses.
Voici comment le didacticiel Java décrit la relation:
La synchronisation est construite autour d'une entité interne connue sous le nom de verrou intrinsèque ou de verrouillage du moniteur. (La spécification de l'API se réfère souvent à cette entité simplement comme un «moniteur».) Les verrous intrinsèques jouent un rôle dans les deux aspects de la synchronisation: imposer un accès exclusif à l'état d'un objet et établir des relations d'avance qui sont essentielles à la visibilité.
Chaque objet est associé à un verrou intrinsèque. Par convention, un thread qui a besoin d'un accès exclusif et cohérent aux champs d'un objet doit acquérir le verrou intrinsèque de l'objet avant d'y accéder, puis libérer le verrou intrinsèque lorsqu'il en a terminé avec eux. On dit qu'un thread possède le verrou intrinsèque entre le moment où il a acquis le verrou et libéré le verrou. Tant qu'un thread possède un verrou intrinsèque, aucun autre thread ne peut acquérir le même verrou. L'autre thread se bloquera lorsqu'il tentera d'acquérir le verrou.
Le but du verrouillage est de protéger les données partagées. Vous utiliseriez des verrous séparés comme indiqué dans l'exemple de code ci-dessus uniquement si chaque verrou protégeait des membres de données différents.