Java:线程中的`while (true) { ... }` 循环不好吗?什么是替代方案?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3367192/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 22:38:21  来源:igfitidea点击:

Java: Is `while (true) { ... }` loop in a thread bad? What's the alternative?

javamultithreadingconcurrencyloopsmessage-passing

提问by Mr. Burgundy

Is while (true) { ... }loop in threads bad? What's the alternative?

while (true) { ... }循环的线程不好?什么是替代方案?

Update; what I'm trying to to...

更新; 我想做什么...

I have ~10,000 threads, each consuming messages from their private queues. I have one thread that's producing messages one by one and putting them in the correct consumer's queue. Each consumer thread loops indefinitely, checking for a message to appear in their queue and process it.

我有大约 10,000 个线程,每个线程都从它们的私有队列中使用消息。我有一个线程一一生成消息并将它们放入正确的消费者队列中。每个消费者线程无限循环,检查是否有消息出现在他们的队列中并处理它。

Inside Consumer.java:

在 Consumer.java 中:

@Override
public void run() {
    while (true) {
        Message msg = messageQueue.poll();
        if (msg != null) {
            ... // do something with the message
        }
    }
}

The Producer is putting messages inside Consumer message queues at a rapid pace (several million messages per second). Consumers should process these messages as fast as possible!

生产者以快速的速度(每秒数百万条消息)将消息放入消费者消息队列中。消费者应该尽快处理这些消息!

Note: the while (true) { ... }is terminated by a KILL message sent by the Producer as its last message. However, my question is about the proper way to do this message-passing...

注意:while (true) { ... }由生产者发送的 KILL 消息作为其最后一条消息终止。但是,我的问题是关于执行此消息传递的正确方法......

Please see the new question, regarding this design.

请参阅有关此设计的新问题

回答by Stefan Kendall

Usually, you'll want to waiton a resource of some kind to do work, which hides actual threading details from you. It sounds like you wanted to implement your own spinlock.

通常,您会希望wait使用某种资源来完成工作,这会向您隐藏实际的线程细节。听起来您想实现自己的spinlock

Here's some tutorial about locking I found I google.

这是我在谷歌上找到的一些关于锁定的教程。

回答by nperson325681

while (!stop_running) { ... }

...perhaps? A some sort of exit flag is often used to control thread running.

...也许?通常使用某种退出标志来控制线程运行。

回答by Eric Petroelje

Not inherently, no. You can always bail using breakor return. Just make sure you actually do (at some point)

不是天生的,不是。您可以随时使用break或保释return。只要确保你真的这样做(在某个时候)

The problem is what happens when your thread has nothing to do? If you just loop around and around checking a condition, your thread will eat up the whole CPU doing nothing. So make sure to use waitto cause your thread to block, or sleepif you don't have anything to waiton.

问题是当您的线程无关时会发生什么?如果你只是循环检查一个条件,你的线程将占用整个 CPU,什么也不做。所以一定要使用wait来导致你的线程阻塞,或者sleep如果你没有任何东西可以wait打开。

回答by Thorbj?rn Ravn Andersen

Depends on the definition of "bad". It means that the person trying to read the code has to look elsewhere for the reason that the loop is terminated. That may make it less readable.

取决于“坏”的定义。这意味着尝试阅读代码的人必须寻找其他地方,因为循环终止。这可能会降低它的可读性。

This mentality taken to the extreme results in the COMEFROM keyword. http://en.wikipedia.org/wiki/COMEFROM

这种极端的心态导致 COMEFROM 关键字。 http://en.wikipedia.org/wiki/COMEFROM

10 COMEFROM 40
20 INPUT "WHAT IS YOUR NAME? "; A$
30 PRINT "HELLO, "; A$
40 REM

回答by Gilles 'SO- stop being evil'

It's better to have the termination condition on the while (...)line, but sometimes the termination condition is something you can only test somewhere deep inside the loop. Then that's what breakis for (or exceptions). In fact maybe your thread must run forever until your program terminates (with System.exit); then while (true)is definitely right.

最好while (...)在行上设置终止条件,但有时终止条件是您只能在循环深处某处进行测试的东西。那么这break就是用于(或例外)的内容。实际上,您的线程可能必须永远运行,直到您的程序终止(使用System.exit);那么while (true)肯定是对的。

But maybe you're asking about what should go inside the loop. You need to make sure to include some blocking operation, i.e., some function call where your thread will wait for someone else (another thread, another program, the OS) to do something. This is typically Condition.waitif you're programming with locks, or reading from a message queue, or reading from a file or network socket, or some other blocking I/O operation.

但也许你在问什么应该进入循环。您需要确保包含一些阻塞操作,即一些函数调用,您的线程将在其中等待其他人(另一个线程、另一个程序、操作系统)执行某些操作。这通常是Condition.wait在您使用锁编程、从消息队列读取、从文件或网络套接字读取或其他一些阻塞 I/O 操作时。

Note that sleepis generally notgood enough. You can't know when other participants are going to do something, so there's no way to avoid waking up too often (thus burning up CPU time needlessly) or too seldom (thus not reacting to events in a timely way). Always design your system so that when a thread has completed its job, it notifies whoever is waiting on that job (often with Condition.signalor by joining).

请注意,这sleep通常不够好。您无法知道其他参与者何时会做某事,因此无法避免醒来太频繁(从而不必要地消耗 CPU 时间)或太少醒来(因此没有及时对事件做出反应)。总是设计你的系统,当一个线程完成它的工作时,它会通知正在等待该工作的人(通常Condition.signal是加入或加入)。

回答by JRL

Instead of looping forever and breaking or returning, you might choose to check the interrupted status.

您可以选择检查中断状态,而不是永远循环并中断或返回。

while (!Thread.currentThread().isInterrupted()) {
    try {
        doWork();
        wait(1000);
    } catch (InterruptedException ex) {
        Thread.currentThread().interrupt();
    }
}

If your threads are tasks managed by an ExecutorService, you can have them all end gracefully simply by calling shutdownNow().

如果您的线程是由 ExecutorService 管理的任务,您可以通过调用 shutdownNow() 来优雅地结束它们。

回答by JustJeff

I usually go with a class attribute boolean called 'done', then the threads' run methods look like

我通常使用名为“done”的类属性布尔值,然后线程的运行方法看起来像

done = false;
while( !done ) {
    // ... process stuff
}

You can then set done=true to kill the loop. This can be done from inside the loop, or you can have another method that sets it, so that other threads can pull the plug.

然后您可以设置 done=true 来终止循环。这可以从循环内部完成,或者您可以使用另一种方法来设置它,以便其他线程可以拔出插头。

回答by Buhake Sindi

while (true)isn't bad if there is a way to exit the loop otherwise the call will run indefinitely.

while (true)如果有办法退出循环也不错,否则调用将无限期运行。

For 10000 threads doing the while(true)call is bad practice...why don't you have a sleep()on the thread to allow other threads to run or an exit strategy if the thread finish running?

对于 10000 个线程进行while(true)调用是不好的做法......为什么sleep()在线程上没有允许其他线程运行或如果线程完成运行的退出策略?

回答by heater

If I were do what you are talking about I would try this:

如果我按照你所说的去做,我会试试这个:

private Object lock = new Object();    

public void run(){
    while(true){
        synchronized(lock){
            Message msg = messageQueue.poll();
            if (msg != null) {
                ... // do something with the message
            }else{
                try{
                    lock.wait();
                }catch(InterruptedException e){
                    e.printStackTrace();
                    continue;
                }
            }
        }
    }
}

This allows you to make sure that you don't get any concurrent modification exepction on your messageQueue, as well as when there is no message you will not be using CPU time in the while(true) loop. Now you just need to make sure that when you do add something to your messageQueue you can call lock.notifyAll()so that the thread will know to run again.

这使您可以确保不会在 messageQueue 上获得任何并发修改异常,并且当没有消息时,您将不会在 while(true) 循环中使用 CPU 时间。现在你只需要确保当你向你的 messageQueue 添加一些东西时你可以调用,lock.notifyAll()这样线程就会知道再次运行。

回答by Tom Hawtin - tackline

It looks like you are busy waiting, assuming a standard BlockingQueue. Use takeinstead of poll.

假设标准BlockingQueue. 使用take代替poll

Other than that, for (;;)is nicer than while (true), IMO.

除此之外,for (;;)while (true)IMO更好。