Java:等待布尔值改变

时间:2013-10-25 13:54:46

标签: java

我正在查看当前的帖子: How to create a thread that waits for a boolean variable to become true?

每个人似乎都彼此不同意,没有人能够充分发挥自己,所以我将以最简单的方式呈现这一点。这是我今天的代码。

boolean connecting = false;

public static void main(String[] args) {
    initUI();
    while(true) {
        if(connecting) {
            connecting = false;
            doSomething();
        }
    };
}

initUI()是一个启动用户界面的方法。当用户单击该类中名为“Connect”的按钮时,它将调用它的动作侦听器并将布尔值“连接”设置为“true”。当它进入if区域时,它会将布尔值重置为“false”并运行我想要的代码。

但这有效......它使用了太多的CPU。

如果我直接将按钮动作侦听器设置为doSomething()方法,则程序会阻塞(并且应该),因为动作侦听器方法需要完成才能重置按钮。然而,doSomething()有循环(它是一个聊天程序),所以它不会返回到原始的(在代码中显示),直到他断开连接。

所以我的问题是,无论如何要“等待”布尔值更改为true。例如听众?

答案:感谢Joni我实施了一个主题。

按钮actionListener现在包括:

(new connectThread()).start();

我的帖子看起来像这样:

public class connectThread extends Thread {
    public void run() {
        ui.btn.setEnabled(false);
        doSomething();
        ui.btn.setEnabled(true);
    }
}

关于问题标题,等待布尔值改变,因为另一个人解释了可以设置事件监听器。

5 个答案:

答案 0 :(得分:2)

返回事件监听器调用doSomething()的代码,但只需更改一次:启动运行doSomething()的新线程,而不是直接调用它。您可以在the Java Tutorial: Simple Background Tasks中找到有关如何执行此操作的完整示例。 SwingWorker API documentation也有一个例子。

答案 1 :(得分:2)

你走错了路 - “忙着等待”,因为你在这里做的几乎总是错误的想法,因为它不必要地耗费CPU时间。

根据我的理解,您希望在不锁定UI线程的情况下按下按钮。正如Joni建议的那样,没有必要让线程在此之前等待 - 只要按下按钮就启动它。如果要确保一次只处理一个按钮,则可以使用具有单个线程的线程池(请参阅SingleThreadExecutor)。

我还想在你的示例代码中指出一个重要的错误:connecting需要变为volatile来告诉编译器该值可能会从另一个线程发生变化。实际上,无法保证您的工作线程会看到值更改,因此即使您在另一个线程中将connecting设置为true,它也可以无限循环。

答案 2 :(得分:2)

  

所以我的问题是,无论如何要“等待”布尔值更改为true。

使用裸boolean变量无法(高效且响应性地)执行此操作。 sleep /测试循环是一个糟糕的解决方案,因为它既昂贵又无响应。如果睡眠间隔很小,你会浪费CPU,如果你把它放大,你的应用程序需要(相对)很长的时间注意状态改变。

但如果通过方法(例如setter)更新boolean,那么您可以将setter编码为:

答案 3 :(得分:0)

你可以放入Thread.sleep(100);在循环中,所以它不是那样的紧密循环,它可以轻松地冻结其余的线程。

您还可以使用等待/通知机制。只需要一个共享的Object,signaller ......有“while(true)”调用“signaller.wait()”,然后,在你的另一个线程设置了标志(它可能不需要)之后,它就可以调用“signaller”。 notifyAll()“将让其他线程运行其下一次迭代,并看到该标志已设置。

答案 4 :(得分:0)

在您的侦听器中,您可以在新线程中运行doSomething(),而不是设置标志。在下面的示例中,ThreadTest实际上是您当前拥有侦听器方法的类(我称之为onClick())。

public class ThreadTest {
    private ExecutorService service;

    public ThreadTest() {
        service = Executors.newFixedThreadPool(10);
    }

    // Button click listener.
    public void onClick() {
        service.submit(new Runnable() {
            @Override
            public void run() {
                doSomething();
            }
        });
    }

    public void doSomething() {}
}