Une méthode est synchronisée lorsqu'elle est marquée par le mot clé
synchronized
.
Lorsqu'une méthode synchronisée est invoquée, le thread courant obtient un verrou sur l'instance référée par cet appel,
à condition que cette instance ne soit pas déjà verrouillée par un autre thread.
Si une instance est déjà verrouillée par un thread,
alors aucun autre thread ne peut avoir un verrou sur cette instance et par conséquent aucun autre thread ne peut exécuter les méthodes synchronisées de cette instance.
Chaque thread qui essaye d'acquérir le verrou sur une instance déjà verouille, sera mis en attente jusqu'à ce que l'instance soit déverrouillée.
Tant que l'exécution de la méthode synchronisée n'est pas terminée,
le thread qui possède le verrou ne libère pas ce verrou et cela même si ce thread n'est plus dans l'état d'exécution (il est endormit par exemple).
class MyClassA {
private String value;
public synchronized void foo() { // méthode synchronisée : instance this
setValue(Thread.currentThread().getName() + " : value");
try {
Thread.sleep(1000); // forcer le thread courant à s'endormir pour donner une chance à l'autre thread de s'exécuter.
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(getValue());
}
private String getValue() {
return value;
}
private void setValue(String value) {
this.value = value;
}
}
public class LocksSynchronizationTest1 {
public static void main(String[] args) {
final MyClassA myClassA = new MyClassA();
Runnable myRunnable1 = new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " (début)");
myClassA.foo(); // le thread courant va acquérir un verrou sur l'instance référée par la variable "myClassA"
System.out.println(Thread.currentThread().getName() + " (fin)");
}
};
Thread myThread1 = new Thread(myRunnable1, "myFirstThread");
Thread myThread2 = new Thread(myRunnable1, "mySecondThread");
myThread1.start();
try {
Thread.sleep(500); // forcer le thread "main" à s'endormir pour être sûr que le thread "myFirstThread" sera exécuté avant le thread "mySecondThread".
} catch (InterruptedException e) {
e.printStackTrace();
}
myThread2.start();
}
}
Résultat d'exécution du code :
myFirstThread (début)
mySecondThread (début)
myFirstThread : value
myFirstThread (fin)
mySecondThread : value
mySecondThread (fin)