Si l'exécution d'un code dépend de l'état d'un objet pour pouvoir lire ou modifier ses attributs et invoquer ses méthodes
alors il est possible dans ce cas de mettre en attente le thread qui s'occupe de l'exécution de ce code,
en attendant que l'autre thread qui manipule l'objet envoie une notification qui informe que l'objet est devenu prêt à être manipuler.
Par exemple, si une application utilise deux threads dont :
- un s'occupe de construire les éléments d'un tableau,
- et l'autre s'occupe de trier les éléments de ce tableau dès que ses éléments ont été tous saisis.
Alors, les deux threads peuvent utiliser les méthodes
wait
et
notify
pour synchroniser l'accès à cet objet.
package com.mtitek.threads;
class MyClass {
private Boolean ready;
private Integer[] elements;
public Boolean getReady() {
return (ready != null && ready);
}
public void setReady(Boolean ready) {
this.ready = ready;
}
public Integer[] getElements() {
return elements;
}
public void setElements(Integer[] elements) {
this.elements = elements;
}
}
public class ObjectWaitNotifyMethodsTest {
public static void main(String[] args) {
final MyClass myClass = new MyClass();
Runnable myRunnable1 = new Runnable() {
@Override
public void run() {
//while(true) {
synchronized (myClass)
{
/** Vérifier que l'objet n'est pas en cours de modification par un autre thread */
while(myClass.getReady()) { // si l'objet est prêt, alors mettre le thread courant en attente
try {
myClass.wait(); // le thread courant va arrêter son exécution et se mettra en attente
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/** code à exécuter par le thread (début) */
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().threadId() + ")");
System.out.println("Initialisation des éléments du tableau (début)");
myClass.setElements(new Integer[] {1,2,3});
System.out.println("Initialisation des éléments du tableau (fin)");
/** code à exécuter par le thread (fin) */
/** Modifier le statut de l'objet + Envoyer une notification pour informer la JVM que le thread courant ne manipule plus cet objet */
myClass.setReady(Boolean.TRUE); // // changement du statut : l'objet est prêt
myClass.notify(); // envoyer une notification pour que la JVM active le thread en attente sur cet objet
}
//}
}
};
Runnable myRunnable2 = new Runnable() {
@Override
public void run() {
//while(true) {
synchronized (myClass)
{
/** Vérifier que l'objet n'est pas en cours de modification par un autre thread */
while(!myClass.getReady()) { // si l'objet n'est pas prêt, alors mettre le thread courant en attente
try {
myClass.wait(); // le thread courant va arrêter son exécution et se mettra en attente
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/** code à exécuter par le thread (début) */
System.out.println(Thread.currentThread().getName() + " (" + Thread.currentThread().threadId() + ")");
System.out.println("Affichage des éléments du tableau (début)");
for (Integer element : myClass.getElements()) {
System.out.println(element);
}
System.out.println("Affichage des éléments du tableau (fin)");
/** code à exécuter par le thread (fin) */
/** Modifier le statut de l'objet + Envoyer une notification pour informer la JVM que le thread courant ne manipule plus cet objet */
myClass.setReady(Boolean.FALSE); // changement du statut : l'objet n'est pas prêt
myClass.notify(); // envoyer une notification pour que la JVM active le thread en attente sur cet objet
}
//}
}
};
Thread myThread1 = new Thread(myRunnable1, "myFirstThread");
Thread myThread2 = new Thread(myRunnable2, "mySecondThread");
myThread1.start();
myThread2.start();
}
}
Résultat d'exécution du code :
myFirstThread (19)
Initialisation des éléments du tableau (début)
Initialisation des éléments du tableau (fin)
mySecondThread (20)
Affichage des éléments du tableau (début)
1
2
3
Affichage des éléments du tableau (fin)