我正在尝试使用多线程来模拟一个简单的恒温器。我在lblDesiredTemp上保存了所需的温度值,另一个标签显示当前温度lblCurrentTemp。当系统中有两个以上的活动线程时,会出现问题。正在等待的线程不会醒来!
这是我的方法:
'private synchronized void ApplySetting()
{
Thread tempetureUpdater = new Thread()
{
@Override
public synchronized void run()
{
txtLog.setText(txtLog.getText() + "\n" + this.getName());
try
{
while(!isDone)
this.wait();
}
catch (InterruptedException ex)
{
txtLog.setText(txtLog.getText() + "\n" + ex.getMessage());
}
int Max = Integer.parseInt(lblDesiredTemp.getText());
int Current = Integer.parseInt(lblCurrentTemp.getText());
txtLog.setText(txtLog.getText() + "\n" + Current + " to " + Max);
if(Current > Max)
{
isDone = false;
for (int i = Current; i > Max; i--)
{
lblGasStatus.setText("Off");
try
{
Thread.sleep(3000);
decreaseTemeture();
}
catch (InterruptedException ex)
{
txtLog.setText(txtLog.getText() + "\n" + ex.getMessage());
}
}
txtLog.setText(txtLog.getText() + "\n" + this.getName() + " done!");
isDone = true;
this.notifyAll();
}
else
{
isDone = false;
for (int i = Current; i < Max; i++)
{
lblGasStatus.setText("On");
try
{
Thread.sleep(3000);
increaseTemeture();
}
catch (InterruptedException ex)
{
txtLog.setText(txtLog.getText() + "\n" + ex.getMessage());
}
}
txtLog.setText(txtLog.getText() + "\n" + this.getName() + " done!");
isDone = true;
this.notifyAll();
}
// Report the result using invokeLater().
SwingUtilities.invokeLater(new Runnable()
{
@Override
public void run()
{
setEnabled(true);
}
});
}
};
tempetureUpdater.start();
}
有什么问题?!
答案 0 :(得分:4)
当系统中有两个以上的活动线程时,会出现问题。正在等待的线程不会醒来!
你期望他们怎么样?你只是在通知“当前”对象,这是一个新线程。当一个线程完成时,它将调用this.notifyAll
,但不会唤醒其他线程。
此外,我强烈敦促你改变关于你如何写这个的其他事情:
ApplySetting
方法名称不遵循Java命名约定。同上各种变量名称。Thread
- 实现Runnable
代替,并将Runnable
传递给线程构造函数wait
个对象上拨打notify
和notifyAll
/ Thread
,因为Thread
会使用该信号自行发送信号run
方法同步几乎总是一个坏主意。鉴于前面的要点,我不希望任何整个方法同步,而是在方法中的各个引用上进行同步invokeLater
)答案 1 :(得分:0)
切勿将run
方法标记为synchronized
。不仅在这里,永远。此外,您的notifyAll
将尝试唤醒它运行的线程。这不起作用。
答案 2 :(得分:0)
您需要更改this
和this.wait()
中的this.notifyAll()
引用,以便它引用外部对象,而不是匿名Thread
类的对象。这可以像编写MyClass.this.wait()
和MyClass.this.notifyAll()
一样简单,其中MyClass
是找到applySettings
方法的类。
但是,我还建议您进行Jon Skeet列出的更改。