2017-09-22 3 views
0

J'ai un test sur le codage de thread java mais j'ai un problème de base .. après des heures d'essai et de recherche, j'ai décidé d'essayer là!Impossible de relacher le verrou avec notifier

Je ne comprends pas pourquoi mon attente est toujours verrouillé même après mon Notify:

Ici vous pouvez trouver mon code:

public class Mymain { 

    public static void main(String[] args) { 

     for(int i=0;i<100;i++){ 
      new ThreadClass(i).start();  
     } 
    } 
} 

public class ThreadClass extends Thread { 
    static boolean ok = false; 
    int id; 

    public ThreadClass(int i) { 
     id = i; 
    } 

    public void run() { 
     System.out.println("Thread start " + id); 
     Last.toDo(id); 
     if (id == 5) 
      try { 
       waiting(); 
      } catch (InterruptedException e) { 
       // TODO Auto-generated catch block 
       e.printStackTrace(); 
      } 

     if (id != 5) 
      awaking(); 

     System.out.println("thread end " + id); 
    } 

    private synchronized void awaking() { 
     // TODO Auto-generated method stub 
     if (ok) { 
      System.out.println("i'm " + id + " and i'm Awaking 5"); 
      ok = false; 
      notify(); 
      System.out.println("I did the notify and i'm " + id); 
     } 
    } 

    private synchronized void waiting() throws InterruptedException { 
     System.out.println("Sleeping"); 
     ok = true; 
     wait(); 
     System.out.println("Awake 5"); 
    } 
} 

Result

Ensuite, il commence en boucle ou il va dans le verrou mort pas sûr .. il devrait juste arrêter le fil avec id = 5 et le prochain thread devrait redémarrer l'id = 5 .. mais le fil 5 ne se réveillent jamais après le notifier ...

Dans le résultat que vous pouvez voir que j'ai eu 2 fils essayant de se réveiller le fil 5 et le fil 5 est toujours en attente depuis le début ^^

+0

Pouvez-vous nous montrer quelle est votre production et ce qu'elle devrait être? –

+0

Pouvez-vous mettre cela dans votre question afin qu'il puisse être formaté pour une analyse facile? –

+0

@WarrenDew Terminé ^^ – JustMe

Répondre

-1

Regardez, je l'ai fait quelques changements à votre code:

  1. Vous ne pouvez pas simplement notify(), vous avertirons à this. Et vous ne pouvez pas juste wait(), vous attendez pour toujours. Vous devez utiliser ces fonctions sur un objet, j'ai donc ajouté un objet Integer (juste pour vous montrer - vous devrez choisir le bon objet).Vous avez compris entre synchronized et static synchronized. Une recherche rapide vous mènerait à une réponse parfaite.
  2. Pourquoi la fonction waiting() est-elle synchronisée? Seul le numéro de fil 5 l'appelle. Pour appeler un Object.notify()/Object.wait(), vous devez déclarer un bloc synchronisé sur l'objet.

Voici quelques code:

public class Threads { 
    public static void main(String[] args) { 
     Integer intObject = new Integer(0); 
     for(int i=0;i<100;i++){ 

      new ThreadClass(i, intObject).start();  
     } 
    } 
} 
class ThreadClass extends Thread { 
    static boolean ok = false; 
    int id; 
    Integer intObject; 
    public ThreadClass(int i, Integer intObject) { 
     id = i; 
     this.intObject = intObject; 
    } 

    public void run() { 
     System.out.println("Thread start " + id); 
     //Last.toDo(id); 
     if (id == 5) 
      waiting(); 
     else 
      awaking(this); 

     System.out.println("thread end " + id); 
    } 

    private static synchronized void awaking(ThreadClass t) { 
     if(ok) { 
      System.out.println("i'm " + t.id + " and i'm Awaking 5"); 
      ok = false; 
      synchronized (t.intObject) { 
        t.intObject.notify(); 
       } 
      System.out.println("I did the notify and i'm " + t.id); 
     } 
    } 
    private void waiting(){ 
     System.out.println("Sleeping"); 
     ok = true; 
     synchronized (intObject) { 
      try { 
       intObject.wait(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
     System.out.println("Awake 5"); 
    } 
} 
+0

Ty pour la réponse très claire ^^ maintenant je l'ai ^^ – JustMe

+1

Ce serait bien, sauf que l'aide d'un entier à verrouiller est une idée horrible. Ce n'est pas comme si c'était nécessaire pour que l'exemple marche. –

+0

Oui, je l'ai écrit, juste pour montrer comment travailler avec synchronisé sur un objet – Yinon

0

Le problème est que vous n'êtes pas appeler notify() sur le même objet que vous avez appelé wait() on. En particulier, le thread 5 appelle wait() sur lui-même, mais thread 8, par exemple, appelle notify() sur lui-même, pas sur le thread 5. En conséquence, le thread 5 n'est jamais notifié.

De même, vous devez créer la variable okvolatile pour vous assurer que lorsqu'un thread le définit, les autres threads peuvent voir le changement. Cela ne vous cause pas de problème dans ce cas particulier, mais cela pourrait causer un problème dans d'autres cas.

+0

Je suis venu à cette fin aussi (première ligne 3) mais je ne comprends pas comment dois-je faire pour notifier thread 5. C'est probablement quelque chose de fondamental, je ignore .. ^^ Ty pour l'aide: D – JustMe

+0

One la façon de le faire serait de remplacer la variable "ok" par une variable Object volatile. Vous vérifieriez nonnull au lieu de vrai, et le thread 5 créerait l'objet et l'attendrait. Les autres threads le notifieraient s'il était là. –

+0

Ouais je l'ai eu ty pour tous ^^ – JustMe

0

Je ne comprends pas pourquoi mon attente est toujours verrouillé même après mon avertir:

attente et de notification travail lorsque le même objet exemple est utilisé. Si par exemple vous avez:

String x1 = "..."; 
String x2 = "..."; 

et fils # 1 fait:

synchronized (x1) { x1.wait(); } 

et fil # 2 fait alors:

synchronized (x2) { x2.wait(); } 

Puis enfilez # 1 sera toujours en attente parce que la notifier était seulement pour x2. Dans votre exemple, le thread avec l'ID 5 attend sur sa propre instance de ThreadClass car vous utilisez la synchronisation des méthodes. Ensuite, lorsque d'autres threads appellent awaking(), ils appellent également notify sur leurs instances de ThreadClass. Si vous voulez que le thread # 5 voit les autres threads notifier, ils doivent partager un objet lock.

Peut-être quelque chose comme:

final Object lock = new Object(); 
for (int id = 0; id < 100; id++){ 
     new ThreadClass(id, lock).start();  
} 
... 
public class ThreadClass extends Thread { 
    private final Object lock; 
    ... 
    public ThreadClass(int id, Object lock) { 
     this.id = id; 
     this.lock = lock; 
    } 
    ... 
    private void awaking() { 
     ... 
     synchronized (lock) { 
      lock.notify(); 
     } 
     ... 
    } 
    private void waiting() throws InterruptedException { 
     ... 
     synchronized (lock) { 
      lock.wait(); 
     } 
     ... 
    } 
} 
+0

Ty pour la réponse très claire ^^ maintenant je l'ai ^^ – JustMe

0

Pourquoi ne pas utiliser notifyAll() méthode? Lorsque vous appelez notify(), cela signifie qu'un seul thread va changer un statut de en attente en runnable, mais il peut y avoir des situations où vous avez plus d'un thread et d'autres threads qui attendent dans la ligne ainsi , ils ne recevront pas cette notification. À mon avis, il est préférable d'utiliser notifyAll.

+0

Ne pensez pas ^^ j'ai résolu comme suggéré par les autres membres ^^ – JustMe

+0

Ce poste ne répond pas à la question avec précision. Si les threads n'utilisent pas le même verrou, peu importe la méthode qu'ils appellent. –