2016-11-21 1 views
0

Je suis étudiant pour un examen d'un livre donné par mon professeur et il y a ce code qui travaille avec Threads et Synchronization: Nous voulons être notifié chaque fois que l'état change (sans manquer un changement d'état).Code avec notify et notifyAll/synchronisation (Aide à comprendre)

public class C { 

    private int state = 0; // the state 
    private boolean modified = false; // to show if the state was changed since actualization 

    public synchronized void printNewState() { 
     while (true) { 
      if (!modified) { 
       wait(); 
      } 
      System.out.println(state); 
      modified = false; 
      notify(); 
     } 
    } 

    public synchronized void setValue(int v) { 
     if (modified) { 
      wait(); 
     } 
     state = v; 
     notify(); 
     modified = true; 
     System.out.println("value set"); 
    } 
} 

Et alors il est écrit:
Cependant, il n'est pas garanti pour la notification() dans la méthode SetValue (int) se réveille le fil printNewState! En Java, nous résoudre ce problème avec l'aide de notifyAll() et prendre un peu d'attente occupé:

public synchronized void printNewState() { 
    while (true) { 
     while (!modified) { 
      wait(); 
     } 
     System.out.println(state); 
     modified = false; 
     **notify();** \\(?) 
    } 
} 

public synchronized void setValue(int v) { 
    while (modified) { 
     wait(); 
    } 
    state = v; 
    notifyAll(); 
    modified = true; 
    System.out.println("value set"); 
} 

Je ne comprends pas pourquoi le notify n'a pas été aussi changé à notifyAll()? Il ne peut pas être garanti que cette notification va à un thread de setValue (int) ???

Merci

Répondre

0

La méthode notify() se réveille un seul thread d'attente, alors que la méthode notifyAll() se réveille tous les fils d'attente. Le problème est qu'avec notify(), le thread qui est réveillé est effectivement aléatoire.

Si un autre thread est accidentellement ou malicieusement sur le même objet, il pourrait recevoir la notification au lieu du thread que vous prévoyez de réveiller. Pour plus d'informations, consultez le this answer. Les commentaires sur cette réponse sont aussi très intéressants.

EDIT

Dans l'exemple de code affiché, la première notify() au sein printNewState() peut gérer qu'une seule mise à jour à la fois, il n'a pas de sens de notifier tous threads en attente d'afficher leurs mises à jour . Le code suppose cependant que seuls les threads appelant setValue(int) attendent.

Depuis public synchronized void setValue(int) est essentiellement le même que synchronized(this) comme première ligne de la méthode, ce qui n'est pas réellement garanti. Tout code qui a une référence à une instance de classe C peut attendre et bousiller le code.

Les actions de synchronisation et d'attente/notification doivent se produire sur un verrou/moniteur d'objet. private final Object monitor = new Object(), synchronized(this.monitor), this.monitor.wait(), this.monitor.notifyAll(), etc.

Je voudrais aussi noter que modified = true doit être placé avant notifyAll() dans setValue(int), sinon d'autres fils de mise à jour en attente se déroulera sans printNewState() remarquer la mise à jour.

En outre, private boolean modified devrait vraiment être private volatile boolean modified, et le même pour private int state, même si un AtomicInteger peut être une meilleure option.

+0

salut Grexis, j'ai édité la question, désolé à ce sujet. Je suis intéressé par votre réponse tho. – ovoxo

+0

@ovoxo, voir mon édition. tl; dr le 'notify()' au lieu de 'notifyAll()' est logique tant que vous êtes sûr que seuls les threads de mise à jour sont en attente. – Grexis

+0

merci beaucoup pour votre réponse, cela m'a beaucoup aidé :) – ovoxo