线程不会唤醒

时间:2012-07-15 07:01:59

标签: java multithreading wait

我正在尝试使用多线程来模拟一个简单的恒温器。我在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(); }

有什么问题?!

3 个答案:

答案 0 :(得分:4)

  

当系统中有两个以上的活动线程时,会出现问题。正在等待的线程不会醒来!

你期望他们怎么样?你只是在通知“当前”对象,这是一个新线程。当一个线程完成时,它将调用this.notifyAll,但不会唤醒其他线程。

此外,我强烈敦促你改变关于你如何写这个的其他事情:

  • 这个大小的匿名内部类迫不及待被分解成一个合适的命名类
  • ApplySetting方法名称不遵循Java命名约定。同上各种变量名称。
  • 扩展Thread - 实现Runnable代替,并将Runnable传递给线程构造函数
  • 通常是一个坏主意。
  • 您不应在wait个对象上拨打notifynotifyAll / Thread,因为Thread会使用该信号自行发送信号
  • 通常最好同步 no 其他代码将用于同步或信令的私有引用
  • 正如Marko的回答所指出的那样,使run方法同步几乎总是一个坏主意。鉴于前面的要点,我不希望任何整个方法同步,而是在方法中的各个引用上进行同步
  • 看起来您正在尝试更新非UI线程中的UI元素;我相信会失败。 (您需要使用invokeLater

答案 1 :(得分:0)

切勿将run方法标记为synchronized。不仅在这里,永远。此外,您的notifyAll将尝试唤醒它运行的线程。这不起作用。

答案 2 :(得分:0)

您需要更改thisthis.wait()中的this.notifyAll()引用,以便它引用外部对象,而不是匿名Thread类的对象。这可以像编写MyClass.this.wait()MyClass.this.notifyAll()一样简单,其中MyClass是找到applySettings方法的类。

但是,我还建议您进行Jon Skeet列出的更改。