Exemple Java de wait, notify et notifyAll

La classe Object en Java contient trois méthodes finales permettant aux threads de communiquer sur l’état de verrouillage d’une ressource. Ces méthodes sont wait(), notify() et notifyAll(). Ainsi, aujourd’hui, nous examinerons les fonctions wait, notify et notifyAll dans un programme Java.

wait, notify et notifyAll en Java

Le thread actuel appelant ces méthodes sur un objet doit posséder le moniteur de l’objet, sinon cela génère une exception java.lang.IllegalMonitorStateException.

wait

Les méthodes d’attente d’objet ont trois variantes, l’une attendant indéfiniment qu’un autre thread appelle la méthode notify ou notifyAll sur l’objet pour réveiller le thread actuel. Les deux autres variantes font attendre le thread actuel pendant une durée spécifique avant de se réveiller.

notify

La méthode notify réveille seulement un thread en attente sur l’objet, et ce thread commence son exécution. Ainsi, s’il y a plusieurs threads en attente pour un objet, cette méthode ne réveillera qu’un seul d’entre eux. Le choix du thread à réveiller dépend de l’implémentation du gestionnaire de threads par le système d’exploitation.

notifyAll

La méthode notifyAll réveille tous les threads en attente sur l’objet, bien que celui qui sera traité en premier dépende de l’implémentation du système d’exploitation. Ces méthodes peuvent être utilisées pour résoudre le problème du producteur-consommateur, où les threads consommateurs attendent les objets dans la file d’attente, et les threads producteurs mettent des objets dans la file d’attente et notifient les threads en attente. Voyons un exemple où plusieurs threads travaillent sur le même objet et où nous utilisons les méthodes wait, notify et notifyAll.

Message

A java bean class on which threads will work and call wait and notify methods.

package com.journaldev.concurrency;

public class Message {
    private String msg;
    
    public Message(String str){
        this.msg=str;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String str) {
        this.msg=str;
    }

}

Waiter

A class that will wait for other threads to invoke notify methods to complete it’s processing. Notice that Waiter thread is owning monitor on Message object using synchronized block.

package com.journaldev.concurrency;

public class Waiter implements Runnable{
    
    private Message msg;
    
    public Waiter(Message m){
        this.msg=m;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        synchronized (msg) {
            try{
                System.out.println(name+" waiting to get notified at time:"+System.currentTimeMillis());
                msg.wait();
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            System.out.println(name+" waiter thread got notified at time:"+System.currentTimeMillis());
            //traiter le message maintenant
            System.out.println(name+" processed: "+msg.getMsg());
        }
    }

}

Notifier

A class that will process on Message object and then invoke notify method to wake up threads waiting for Message object. Notice that synchronized block is used to own the monitor of Message object.

package com.journaldev.concurrency;

public class Notifier implements Runnable {

    private Message msg;
    
    public Notifier(Message msg) {
        this.msg = msg;
    }

    @Override
    public void run() {
        String name = Thread.currentThread().getName();
        System.out.println(name+" started");
        try {
            Thread.sleep(1000);
            synchronized (msg) {
                msg.setMsg(name+" Notifier work done");
                msg.notify();
                // msg.notifyAll();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        
    }

}

WaitNotifyTest

Classe de test qui créera plusieurs threads Waiter et Notifier et les lancera.

package com.journaldev.concurrency;

public class WaitNotifyTest {

    public static void main(String[] args) {
        Message msg = new Message("process it");
        Waiter waiter = new Waiter(msg);
        new Thread(waiter,"waiter").start();
        
        Waiter waiter1 = new Waiter(msg);
        new Thread(waiter1, "waiter1").start();
        
        Notifier notifier = new Notifier(msg);
        new Thread(notifier, "notifier").start();
        System.out.println("All the threads are started");
    }

}

Lorsque nous invoquerons le programme ci-dessus, nous verrons la sortie ci-dessous, mais le programme ne se terminera pas car il y a deux threads en attente sur l’objet Message et la méthode notify() n’en a réveillé qu’un, l’autre thread attend toujours d’être notifié.

waiter waiting to get notified at time:1356318734009
waiter1 waiting to get notified at time:1356318734010
All the threads are started
notifier started
waiter waiter thread got notified at time:1356318735011
waiter processed: notifier Notifier work done

Si nous commentons l’appel à notify() et décommentons l’appel à notifyAll() dans la classe Notifier, la sortie produite sera la suivante.

waiter waiting to get notified at time:1356318917118
waiter1 waiting to get notified at time:1356318917118
All the threads are started
notifier started
waiter1 waiter thread got notified at time:1356318918120
waiter1 processed: notifier Notifier work done
waiter waiter thread got notified at time:1356318918120
waiter processed: notifier Notifier work done

Étant donné que la méthode notifyAll() réveille les deux threads Waiter, le programme se termine et se termine après l’exécution. C’est tout pour wait, notify et notifyAll en Java.

Source:
https://www.digitalocean.com/community/tutorials/java-thread-wait-notify-and-notifyall-example