2010-03-16 82 views
4

我在我的应用程序中使用了多个线程。基本上我有一个组合框,当选择收件箱时,p1恢复并且p2被暂停,并且在选择发送时,p2开始并且p1停止。下面是代码(我敢肯定,它并不完美)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(); 
        } 
       } 
      } 
     }); 

和P1和P2我有这样的while循环内:

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

...因为它是它现在的工作(我是一个初学者)。在组合框中按下发送时,我得到一个IllegalStateMonitorException。任何人都可以帮我解决问题吗?

感谢和问候, Krt_Malta

回答

6

的问题是在这里:

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

你正在做p2.notify()当你没有在p2锁(您必须持有监视器打电话通知上它)。将synchronized(p1)更改为synchronized(p2)。此外,还需要反转另一个同步子句,这也是错误的。所以,作为一个例子:

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

此外,您的其他代码是有点不妥太,这是非常不好的做法,整个循环内锁定,使更多的原子。

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

附加的优化,避免synchronised如果可能的话:

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(); 
    } 
} 

制作的续场volatile这里,和镜if语句适当的其他部分。

编辑:回顾一下并与最近面临的并发错误作斗争时,实现此模式的任何人都可能面临无限等待的问题,如果被半锁定锁定的对象正在被条件是while循环(这是因为在评估有条件语句和强制等待语句之间状态可能会发生变化)。在这种情况下,将同步块放置在循环外部的外部的上。

0

在这段代码

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

你上同步p1p2调用notify(),从而导致异常。

-1

你不能在awt事件调度线程中等待,否则将阻止你的整个应用程序。阅读关于http://en.wikipedia.org/wiki/Event_dispatching_thread

此外,你不应该使用原始线程,除非你真的知道你在做什么。检查出http://java.sun.com/javase/6/docs/api/java/util/concurrent/package-summary.html并在Executors

+0

上阅读他没有在AWT线程中等待。他只是打电话给notify()。此外,我建议调用notifyAll()以确保等待的线程得到通知。 – 2010-03-16 18:06:48

+0

通过在EDT中可以导致等待的任何地方使用同步。这不正确吗? – Pyrolistical 2010-03-16 18:09:24

+0

这是守卫的锁;他们的锁在等待时退回到半锁。这允许另一个线程抓住锁,然后恢复另一个线程。无论哪种方式,如果您使用notify()或wait(),则您*必须*锁定对象。有关详细信息,请参阅http://www.java2s.com/Code/Java/Threads/Threadnotify.htm。 – 2010-03-16 18:22:52