Java线程问题

4

我在我的应用程序中使用了多线程。基本上,我有一个组合框,选择收件箱时,p1恢复并且p2被暂停;选择发送时,p2开始并且p1停止。以下是代码(我确定它不完美)

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

3个回答

6

问题出在这里:

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

当你没有锁定p2时,执行p2.notify()会出现问题(必须在持有监视器的情况下调用notify)。将synchronized(p1)更改为synchronized(p2)。此外,您还需要反转另一个同步子句,因为它也存在问题。因此,例如: ```html

您在执行p2.notify()时未锁定p2(必须在持有监视器的情况下调用notify)。将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) {
       }
    }
}

更多优化,尽可能避免使用synchronized

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

将此处的cont字段设为volatile,并在if语句的另一部分进行相应的镜像处理。 注:回顾这个实现过程,并且与最近遇到的并发错误进行斗争时,如果正在查看while循环条件中被锁定和半锁定对象的人可能会遇到无限等待的问题(这是因为在评估条件和等待语句强制执行之间有一个状态可以改变的差距)。在这种情况下,请将同步块放置在循环的外部

0
在这段代码中
                synchronized(p1)
                {
                    p2.cont = true;
                    p2.notify();
                }

你正在对 p1 进行同步,但却在 p2 上调用了 notify(),这导致了异常。


-1

他并没有在AWT线程中等待。他只是调用了notify()。此外,我建议调用notifyAll()以确保等待的线程得到通知。 - Chris Dennett
在EDT中任何地方使用synchronized都可能导致等待,这是不是正确的呢? - Pyrolistical
这就是保护锁的作用:在等待时,它的锁会回退到半锁状态。这样可以让另一个线程获取锁并恢复其他线程。无论哪种情况,如果您使用notify()或wait(),都必须在对象上拥有锁。有关详细信息,请参见http://www.java2s.com/Code/Java/Threads/Threadnotify.htm。 - Chris Dennett
是的,但这是在EDT的上下文中。您假设modifyText可以被调用两次,这是错误的。 - Pyrolistical
可以调用两次,因为p1和p2应该由半锁定锁定(假设他修改了他的代码)。由于有错误,已编辑帖子(他需要修改更多的代码)。 - Chris Dennett

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接