0

我目前正在编写一个带有 Swing-Interface 的小型应用程序,其中包含一堆按钮。现在我的问题如下:启动应用程序后,调用一个方法,我想等待两个按钮被按下,然后正常进行。我有两个线程,一个是主线程,另一个是为了等待两个按钮被按下而创建的。对于按钮,我像往常一样添加了一个 ActionListener,它将一个变量增加一个,并在变量为 2 时调用一个唤醒另一个的方法。
所以这是我的代码:

int counter = 0;
static Thread thread1;
static Thread thread2;

public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                thread1 = new Thread() {
                    @Override
                    public void run() {
                        MainFrame frame = new MainFrame();
                        frame.setVisible(true);
                        start();
                    }
                };
                thread1.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}

public MainFrame() {
    //other stuff and similar Listeners
    JButton button1 = new JButton();
    button1.addActionListener(new ActionAdapter() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            count++;
            notifyIfTwo();
        }
    });
}

public void notifyIfTwo() {
    if (count == 2) {
        synchronized(thread2) {
            notifyAll();
        }
    }
}

public void start() {
    thread2 = new Thread() {
        @Override
        public void run() {
            try {
                synchronized(thread1) {
                    thread2.wait();
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    };
    thread2.start();    
    //other stuff
}

不管我怎么做,我总是得到一个 IllegalMonitorStateException。我还尝试使用 thread2 中的循环来检查计数器是否为 2,但我得到了相同的结果。我认为这与同步问题有关,但我对整个多线程的东西还是陌生的,所以如果你能给我一些指向正确方向的指示,我将不胜感激。
或者,也许您甚至知道一种更简单的方法来解决整个“等到按下两个按钮”的问题?

提前致谢,
问候

4

4 回答 4

3

使用CountDownLatch. 它允许等待给定数量的countDown()调用。

Thread.wait();在您的代码中没有意义,它无法编译。该wait方法可以应用于您正在同步的对象。

于 2013-03-21T12:31:08.107 回答
1

我认为导致您出现异常的原因是 thread1 正在从 UI 线程访问 GUI 组件。解决此问题的一种方法是摆脱 thread1。让您的 onClick(或 actionPerformed)处理程序增加变量。让 thread2 在等待(比如 500 毫秒)后循环并监视变量值。

因此,您可以稍后使用 runnable 保留调用,但在外部 run 方法中执行工作,例如:

public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
    public void run() {
        try
        {
            MainFrame frame = new MainFrame();
            frame.setVisible(true);
            start();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
});
}

public void start() {
thread2 = new Thread() {
    @Override
    public void run() {
        try {
                while (keepGoing)
                {
                    thread2.sleep(500);
                    if (variableIncremented)
                    {
                        // doSomething();
                        // reset variable, or set keepGoing = false
                    }
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
};
    thread2.start();    
    //other stuff
}
于 2013-03-21T12:30:57.037 回答
1

重点是:

    synchronized(thread2) {
        notifyAll();
    }

您正在通知所有等待的线程this,但您没有监视器this。对于所有等待/通知/通知全部,代码必须是:

 synchronized (foo) {
    foo.wait();    // or foo.notify()
 }

同样,稍后您将拥有:

  synchronized(thread1) {
     thread2.wait();
  }

您不能在 obj1 上同步并在 obj2 上等待,除非 obj1 == obj2。

于 2013-03-21T12:36:31.207 回答
0

好的,现在想通了。剩下的问题是我没有足够严格地将 GUI 线程和包含逻辑的另一个线程分开(在我发布的代码之外)。
感谢所有帮助我找出 IllegalMonitorStateException 的人。
我现在像有人建议的那样使用了 CountDownLatch,它就像一个魅力。

于 2013-03-21T14:18:34.900 回答