3 votes

Moniteurs et blocs synchronisés en Java (il semble que deux threads possèdent un moniteur en même temps)

J'essaie de comprendre le synchronized() dans le programme que j'ai écrit à la fin de ce billet.

Il y a deux fils ( o y k ) qui utilisent une lock comme moniteur pour wait/notify.

o attend k pour commencer, à l'intérieur du bloc synchronisé suivant :

synchronized (lock) {
    lock.wait(); // wait for K to be ready
}

k notifie ensuite o et attend qu'il s'imprime à l'intérieur de ce bloc :

synchronized (lock) {
    lock.notify(); // tell O to print
    lock.wait(); // wait for O to print
}

Ma question est de savoir comment k entrer dans le bloc synchronisé avec lock ? Ne devrait-on pas o propre lock (puisqu'il a appelé wait() ) ? Le site Java Tutorial dit :

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 bloque lorsqu'il tente d'acquérir le verrou.

Voici le programme complet :

public class OK implements Runnable {

    private static final Object lock = new Object(); // monitor for wait/notify

    private boolean isO;

    public OK(boolean b) {
        isO = b;
    }

    public static void main(String[] args) throws InterruptedException {

        Thread o = new Thread(new OK(true));
        Thread k = new Thread(new OK(false));
        o.start();
        k.start();
        k.join(); // when k is done, we're done
        System.out.println("Done.");

    }

    public void run() {

        // run method is called for both o and k, so we separate the logic
        try {
            if (isO) {
                doO();
            } else {
                doK();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }

    // O thread logic
    private void doO() throws InterruptedException {

        // K needs to be ready before I start
        synchronized (lock) {
            lock.wait(); // wait for K to be ready
        }

        System.out.print("O");
        synchronized (lock) {
            lock.notify(); // tell K I printed
        }
    }

    // K thread logic
    private void doK() throws InterruptedException {

        // O is waiting for me to start

        synchronized (lock) {
            lock.notify(); // tell O to print
            lock.wait(); // wait for O to print
        }
        System.out.println("K");
    }

}

6voto

Wouter Coekaerts Points 3494

Lock.wait libère le moniteur. Voir le Object.wait() javadoc :

Le thread actuel doit posséder le moniteur de cet objet. Le thread libère la propriété de ce moniteur et attend qu'un autre thread notifie aux threads qui attendent le moniteur de cet objet de se réveiller, soit par un appel à la méthode notify, soit par la méthode notifyAll. Le thread attend alors de pouvoir récupérer la propriété du moniteur et reprend l'exécution.

L'intuition peut vous dire que "synchronisé (verrou)" signifie qu'il maintient ce verrou pendant tout le bloc qu'il enveloppe ; mais ce n'est pas ainsi que cela fonctionne.

2voto

Sebastian Points 1462

En complément de la réponse de @Wouter Coekaerts, il est considéré comme une bonne pratique de toujours avoir un appel à wait() à l'intérieur d'une boucle car des "réveils intempestifs" pourraient se produire. Voir : THI03-J. Toujours invoquer les méthodes wait() et await() à l'intérieur d'une boucle par exemple.

1voto

Ankur Shanbhag Points 4125

Le comportement n'est pas assuré/garanti lorsqu'il s'agit de multithreading. Il dépend entièrement de l'ordonnanceur qui invoque un thread à partir d'un pool de threads en cours d'exécution. Vous ne pouvez absolument pas garantir que le fil O sera invoqué avant le fil K simplement parce que vous l'avez lancé avant le fil K. Il se peut même que le planificateur prenne le fil K et commence à l'exécuter en premier et qu'il acquière donc un verrou avant le fil O.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X