2010-03-16 2 views
4

J'utilise plusieurs threads dans mon application. Fondamentalement, j'ai une zone de liste déroulante et lors de la sélection de la boîte de réception, p1 reprend et p2 est suspendu et lors de la sélection de Envoyer, p2 démarre et p1 s'arrête. Voici le code (je suis sûr que ce n'est pas parfait)Problème de threads Java

public void modifyText(ModifyEvent e) { 
       if (combo.getText().equals("Inbox")) 
       { 
        synchronized(p2) 
        { 
         p2.cont = false; 
        } 
        table.removeAll(); 
        synchronized(p1) 
        { 
         p1.cont = true; 
         p1.notify(); 
        } 
       } 


       else if (combo.getText().equals("Sent")) 
       { 
        synchronized(p2) 
        { 
         p1.cont = false; 
        } 
        table.removeAll(); 
        synchronized(p1) 
        { 
         p2.cont = true; 
         p2.notify(); 
        } 
       } 
      } 
     }); 

et pour P1 et P2 ont ce que je l'intérieur de leur boucle while:

synchronized (this) { 
      while (cont == false) 
       try { 
        wait(); 
       } catch (Exception e) { 
       } 
     } 

... Comme il est il travaille maintenant (Je suis un débutant aux discussions). En appuyant sur Envoyé dans la zone de liste déroulante, j'obtiens une exception IllegalStateMonitorException. Quelqu'un pourrait-il m'aider à résoudre le problème plz?

Merci et salutations, Krt_Malta

Répondre

6

le problème est ici:

synchronized(p1) 
{ 
    p2.cont = true; 
    p2.notify(); 
} 

Vous faites p2.notify() lorsque vous n'avez pas un verrou sur p2 (vous devez tenir le moniteur pour appeler informer sur il). Remplacez synchronized(p1) par synchronized(p2). De plus, vous devez inverser l'autre clause synchronisée, qui est également défectueuse. Ainsi, à titre d'exemple:

synchronized(p1) 
{ 
    p1.cont = false; 
    // p1.notify(); <- do you need this here? 
} 
table.removeAll(); 
synchronized(p2) 
{ 
    p2.cont = true; 
    p2.notify(); 
} 

De plus, votre autre code est un peu mal aussi, il est très mauvaise pratique à enfermer dans une boucle entière, faire un peu plus atomique.

while (!cont) { 
    synchronized (this) { 
     try { 
      wait(); 
     } catch (Exception e) { 
     } 
    } 
} 

optimisation supplémentaires, éviter synchronised si possible:

if (p1.cont) { 
    synchronized(p1) 
    { 
     p1.cont = false; 
     // p1.notify(); <- do you need this here? 
    } 
} 
table.removeAll(); 

if (!p2.cont) { 
    synchronized(p2) 
    { 
     p2.cont = true; 
     p2.notify(); 
    } 
} 

pour que le champ suite volatile ici et miroir pour l'autre partie de l'instruction if, selon le cas. Edit: en repensant à cela et en luttant contre un bug de simultanéité auquel j'étais récemment confronté, quiconque implémentant ce pattern pourrait rencontrer un problème avec une attente infinie, si un objet verrouillé & est verrouillé par le conditionnel de la boucle while (car il existe un écart où l'état peut changer entre l'évaluation du conditionnel et l'imposition de l'instruction wait). Dans ce cas, placez le bloc synchronisé sur le en dehors de de la boucle.

0

Dans ce code

   synchronized(p1) 
       { 
        p2.cont = true; 
        p2.notify(); 
       } 

Vous synchronisez sur p1 mais appelant notify() sur p2, ce qui conduit à l'exception.

-1

Vous ne pouvez pas attendre dans le fil d'expédition de l'événement awt, sinon cela va bloquer toute votre application. Lire à propos de http://en.wikipedia.org/wiki/Event_dispatching_thread

De même, vous ne devez pas utiliser de threads bruts, sauf si vous savez vraiment ce que vous faites. Découvrez http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html et lire sur Executors

+0

Il n'attend pas dans le thread AWT. Il appelle juste notify(). De plus, je vous recommande d'appeler notifyAll() pour vous assurer que le thread en attente est averti. –

+0

En utilisant synchronisé n'importe où dans l'EDT qui peut provoquer une attente. N'est-ce pas vrai? – Pyrolistical

+0

Voilà à quoi servent les verrous gardés; leur verrou recule jusqu'à une demi-serrure en attendant. Cela permet à un autre thread de saisir le verrou puis de reprendre l'autre thread. De toute façon, si vous utilisez notify() ou wait(), vous devez * avoir * un verrou sur l'objet. Voir http://www.java2s.com/Code/Java/Threads/Threadnotify.htm pour plus de détails. –