Java中的多线程:等到按下两个按钮?

时间:2013-03-21 12:17:01

标签: java multithreading

我目前正在编写一个包含一堆按钮的Swing-Interface的小应用程序。现在我的问题如下:启动应用程序后,调用一个方法,我想等待按下两个按钮然后继续正常。我有两个线程,一个是主线程,另一个是创建,只是等到按下两个按钮。对于按钮,我添加了一个像往常一样的ActionListener,它将变量增加1并调用一个方法,当变量为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中的一个循环,它将检查计数器是否是两个但我得到了相同的结果。我认为这与同步问题有关,但我对整个多线程的东西都很陌生,所以如果你能给我一些指向正确方向的话,我将不胜感激。
或者你甚至可能知道一个更简单的方法来完成整个“等到按下两个按钮”-problem?

提前感谢,
此致

4 个答案:

答案 0 :(得分:3)

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

代码中的

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

答案 1 :(得分:1)

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

所以你可以稍后用runnable保持调用,但是在外部运行方法中做的工作如下:

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
}

答案 2 :(得分:1)

重点是:

    synchronized(thread2) {
        notifyAll();
    }

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

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

同样,以后你有:

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

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

答案 3 :(得分:0)

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