2

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

有什么问题?!

4

3 回答 3

4

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

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

此外,我强烈敦促您更改有关如何编写此内容的其他内容:

  • 这种规模的匿名内部类迫切需要分解成一个适当的命名类
  • ApplySetting方法名称不遵循 Java 命名约定。同上各种变量名。
  • 扩展通常是一个坏主意Thread-Runnable改为实现,并将其传递Runnable给线程构造函数
  • 你不应该在对象上调用waitnotify/ ,因为它用于信号本身notifyAllThreadThread
  • 在私有引用上进行同步通常是一个好主意,其他代码不会将其用于同步或信令
  • 正如 Marko 的回答中所指出的,使run方法同步几乎总是一个坏主意。鉴于前面的要点,我不希望同步任何整个方法,而是同步方法中的单个引用
  • 看起来您正在尝试在非 UI 线程中更新 UI 元素;我相信那会失败。(你需要使用invokeLater
于 2012-07-15T07:08:25.693 回答
0

您需要更改this引用,this.wait()以便this.notifyAll()它引用外部对象,而不是匿名Thread类的对象。这可以像编写MyClass.this.wait()and一样简单,你的方法MyClass.this.notifyAll()所在MyClass的类在哪里。applySettings

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

于 2012-07-15T07:28:12.510 回答
0

run永远不要将方法标记为synchronized. 不仅在这里,永远。此外,您notifyAll将尝试唤醒它运行的线程。这是行不通的。

于 2012-07-15T07:05:07.553 回答