Java 同步不工作

Java 同步不工作,java,multithreading,Java,Multithreading,我已经创建了一个非常简单的计算器,用于学习,我想让一个“播音员”在JTextArea中宣布操作的结果。这个项目的目的是利用我们在大学里学到的东西。我有一个自己的announcement类,它实现runnable并同步我的calc对象,它应该附加结果,但什么也没有发生 程序运行良好,因此我已将代码剥离到相关部分: 播音员类中的run方法: public void run() { calc.getAnnouncementJTF().append("Announcer thread h

我已经创建了一个非常简单的计算器,用于学习,我想让一个“播音员”在JTextArea中宣布操作的结果。这个项目的目的是利用我们在大学里学到的东西。我有一个自己的announcement类,它实现runnable并同步我的calc对象,它应该附加结果,但什么也没有发生

程序运行良好,因此我已将代码剥离到相关部分:

播音员类中的run方法:

    public void run()
{
    calc.getAnnouncementJTF().append("Announcer thread has been initialized...\n");
    calc.getAnnouncementJTF().append("Hi. My name is " + this.getName() + " and my purpose is to " +
            "announce the results of your operations as soon as they are ready. \r\n");
    while(true){
        synchronized(calc){
            try
            {
                calc.wait();
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }
        }
        calc.getAnnouncementJTF().append(String.valueOf(calc.getResult() + "\n"));
    }

}
下面是将执行计算并通知所有等待对象的条件:

            else if(e.getSource() == sumButton && Numbers.size() != 0)
        {
            if(!actualNumber.getText().equals("")){
                Numbers.add(new Double(actualNumber.getText()));
                addToResults = previousNumbers.getText() + " " + actualNumber.getText();
            } else {
                addToResults = previousNumbers.getText().substring(0, previousNumbers.getText().length() - 2);
            }
            currentResult = performCalculation(Numbers, Operators);
            previousCalcs.append(addToResults + " = " + String.valueOf(currentResult) + "\r\n");
            // Clear both lists and add the result to a cleared
            // list for further calculation on it.
            Operators.clear();
            Numbers.clear();
            actualNumber.setText(String.valueOf(currentResult));
            previousNumbers.setText("");
            resultExist = true;
            synchronized(this){
                notifyAll();
            }
        }
主要方法

public static void main(String[] args){
    Announcer announcer = new Announcer();
    Calculator calc = new Calculator(announcer);

    calc.setTitle("Calculator");
    calc.setSize(360, 900);
    calc.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    calc.setLocationRelativeTo(null);
    calc.setVisible(true);
    calc.setResizable(false);

    announcer.setCalculator(calc); announcer.setName("Sam");
    announcer.setAge(28); announcer.setLength(182.5);

    Thread announcerThread = new Thread(announcer);
    announcerThread.start();
}
正如我前面提到的,代码运行良好。我唯一的问题是,announcer类中run方法的这一部分没有运行:

calc.getAnnouncementJTF().append(String.valueOf(calc.getResult() + "\n"));

正如注释中已经指出的,修改UI状态的代码必须在事件分派线程中执行。但我想,你已经在EDT中进行更新了。在这种情况下,问题是您正在运行无限循环轮询以获取新结果,并将它们附加到
JTextField
。这是可行的,但是您正在使用无限循环阻塞事件调度线程,因此它没有机会重新绘制受影响的UI区域

一个简单的解决方案是让计算线程使用
EventQueue.invokeLater
调度
Runnable
s,它只执行一次更新并返回。另一种方法是让Swing
计时器
定期执行一个
Runnable
,它将在
calc
对象上同步,并请求当前结果。请注意,在后一种情况下,与您现在的代码一样,您可能会错过更新,因为
notifyAll
不能保证与其他线程的
wait
调用配对


此外,仅为
wait
notify
调用进行同步是不够的。修改结果的代码和检索结果的代码(调用
calc.getResult()
也必须在
synchronized
块内。

类中存在同步问题,但也存在一个大的Swing问题:Swing组件可能无法从EDT以外的线程访问。读取将
calc.getAnnouncementJTF().append()移动到
synchronized
块中。正如@JBNizet所述,我们使用
SwingUtilities.invokeAndWait()
更新EDT之外的文本。“条件”在哪里?