2

我正在查看当前线程: 如何创建一个等待布尔变量变为真的线程?

每个人似乎都彼此不同意,没有人足够解释自己,所以我将以最简单的方式介绍这一点。这是我今天的代码。

boolean connecting = false;

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

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

但是,这可行……它使用了太多的CPU。

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

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

回答:感谢 Joni,我实现了一个线程。

按钮 actionListener 现在包括:

(new connectThread()).start();

我的线程看起来像这样:

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

至于问题标题,等待布尔值改变,正如另一个人解释的那样,可以设置一个事件监听器。

4

5 回答 5

3

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

你不能用一个裸boolean变量来(有效地和响应地)做到这一点。/ 测试循环是一个sleep糟糕的解决方案,因为它要么很昂贵,要么没有响应。如果睡眠间隔很小,则会浪费 CPU,如果将其增大,则应用程序需要(相对)较长的时间才能注意到状​​态变化。

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

于 2013-10-25T14:12:01.680 回答
2

回到事件侦听器调用的代码doSomething(),但有一个变化:启动一个运行的新线程,doSomething()而不是直接调用它。您可以在Java 教程:简单后台任务中找到如何执行此操作的完整示例。SwingWorker API 文档也有一个示例。

于 2013-10-25T14:00:24.393 回答
2

你在错误的轨道上 - 你在这里做的“忙于等待”几乎总是错误的想法,因为它只是不必要地消耗 CPU 时间。

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

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

于 2013-10-25T14:10:41.663 回答
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() {}
}
于 2013-10-25T14:20:50.983 回答
0

您可以放入 Thread.sleep(100); 在循环中,所以它不是那种紧密的循环,它可以很容易地冻结其余的线程。

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

于 2013-10-25T14:01:31.397 回答