我在我的应用程序中使用了多个线程。基本上我有一个组合框,选择收件箱后,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) {
}
}
... 现在它正在工作(我是线程的初学者)。在组合框中按下 Sent 时,我得到一个 IllegalStateMonitorException。有谁能帮我解决这个问题吗?
感谢和问候, Krt_马耳他
最佳答案
问题出在这里:
synchronized(p1)
{
p2.cont = true;
p2.notify();
}
当您还没有锁定p2
时,您正在执行p2.notify()
(您必须按住监视器才能在其上调用notify)。将 synchronized(p1)
更改为 synchronized(p2)
。此外,您还需要反转其他 synchronized 子句,这也是有问题的。因此,举个例子:
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 循环(这是因为在评估条件和执行等待语句之间存在状态可以更改的间隙)。在这种情况下,将同步块(synchronized block)放在循环的外部。
关于Java线程问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2456846/