Java:线程中的 while (true) { ... }` 循环不好吗?还有什么选择?
线程中的 while (true) { ... } 循环是否不好?还有什么选择呢?
更新;我正在尝试...
我有大约 10,000 个线程,每个线程都消耗来自其私有队列的消息。我有一个线程一条一条地生成消息并将它们放入正确的消费者队列中。每个消费者线程无限循环,检查消息是否出现在其队列中并处理它。
Consumer.java 内部:
@Override
public void run() {
while (true) {
Message msg = messageQueue.poll();
if (msg != null) {
... // do something with the message
}
}
}
生产者快速地将消息放入消费者消息队列中(每秒几百万条消息)。消费者应该尽快处理这些消息!
注意:while (true) { ... }
由生产者发送的 KILL 消息作为其最后一条消息终止。但是,我的问题是关于执行此消息传递的正确方法...
请参阅关于此设计的新问题。
Is while (true) { ... }
loop in threads bad? What's the alternative?
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.
Inside 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...
Please see the new question, regarding this design.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
您可以选择检查中断状态,而不是永远循环并中断或返回。
如果您的线程是由 ExecutorService 管理的任务,您只需调用 shutdownNow() 即可让它们全部正常结束。
Instead of looping forever and breaking or returning, you might choose to check the interrupted status.
If your threads are tasks managed by an ExecutorService, you can have them all end gracefully simply by calling shutdownNow().
...也许?某种退出标志通常用于控制线程运行。
...perhaps? A some sort of exit flag is often used to control thread running.
不是天生的,不是。您始终可以使用
break
或return
进行保释。只要确保你确实(在某些时候)这样做了问题是当你的线程无事可做时会发生什么?如果你只是循环检查一个条件,你的线程就会耗尽整个 CPU 而不做任何事。因此,请确保使用
wait
来让线程阻塞,或者如果没有任何内容可以wait
则使用sleep
。Not inherently, no. You can always bail using
break
orreturn
. Just make sure you actually do (at some point)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
wait
to cause your thread to block, orsleep
if you don't have anything towait
on.取决于“坏”的定义。这意味着尝试阅读代码的人必须在其他地方查找循环终止的原因。这可能会降低它的可读性。
这种心态发挥到了极致,导致了 COMEFROM 关键字的诞生。 http://en.wikipedia.org/wiki/COMEFROM
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
首先,Dough Lea 对这个问题的直接回答:
http://gee.cs.oswego.edu/dl/html/j9mm。 html
Thead.onSpinWait 是随 Java 9 引入的。它可能看起来像这样。
https://docs.oracle。 com/javase/9/docs/api/java/lang/Thread.html#onSpinWait--
First up, the straight answer to this problem by Dough Lea:
http://gee.cs.oswego.edu/dl/html/j9mm.html
Thead.onSpinWait was introduced with Java 9. It could look like this.
https://docs.oracle.com/javase/9/docs/api/java/lang/Thread.html#onSpinWait--
通常,您需要
等待
某种资源来完成工作,这会向您隐藏实际的线程详细信息。听起来您想实现自己的 spinlock。这是我在 google 上找到的一些有关锁定的教程。
Usually, you'll want to
wait
on 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.Here's some tutorial about locking I found I google.
最好将终止条件放在
while (...)
行上,但有时终止条件只能在循环深处的某个位置进行测试。这就是break
的用途(或例外)。事实上,也许你的线程必须永远运行,直到你的程序终止(使用System.exit
);那么while (true)
绝对是正确的。但也许您会问循环内应该包含什么内容。您需要确保包含一些阻塞操作,即某些函数调用,您的线程将等待其他人(另一个线程、另一个程序、操作系统)执行某些操作。如果您正在使用锁进行编程,或者从消息队列中读取,或者从文件或网络套接字中读取,或者进行其他一些阻塞 I/O 操作,则这通常是
Condition.wait
。请注意,
睡眠
通常不够。您无法知道其他参与者何时会做某事,因此无法避免醒来太频繁(从而不必要地消耗 CPU 时间)或太少醒来(因此无法及时对事件做出反应)。始终设计您的系统,以便当线程完成其作业时,它会通知正在等待该作业的任何人(通常使用Condition.signal
或通过加入)。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 whatbreak
is for (or exceptions). In fact maybe your thread must run forever until your program terminates (withSystem.exit
); thenwhile (true)
is definitely right.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.wait
if 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.Note that
sleep
is generally not good 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 withCondition.signal
or by joining).如果有办法退出循环,那么 while (true) 也不错,否则调用将无限期地运行。
对于 10000 个线程来说,执行
while(true)
调用是不好的做法...为什么不在线程上使用sleep()
来允许其他线程运行或如果线程完成运行,退出策略是什么?while (true)
isn't bad if there is a way to exit the loop otherwise the call will run indefinitely.For 10000 threads doing the
while(true)
call is bad practice...why don't you have asleep()
on the thread to allow other threads to run or an exit strategy if the thread finish running?虽然以上所有答案都是正确的,但我想建议这个,因为我自己也遇到过这种情况:
您可以使用一个标志:
稍后,在完成从缓冲区或数据文件的读取后,确保 isRunning 设置为 false。
Although all the above answers are correct, I want to suggest this one as I came across this situation myself:
You can use a flag say:
Later, make sure that isRunning is set to false after you are done reading from the buffer or data file.
我通常使用一个名为“done”的类属性布尔值,然后线程的运行方法看起来像
你可以设置done=true来终止循环。这可以从循环内部完成,或者您可以使用另一种方法来设置它,以便其他线程可以拔出插头。
I usually go with a class attribute boolean called 'done', then the threads' run methods look like
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.
假设有一个标准的
BlockingQueue
,您似乎正忙于等待。使用take
而不是poll
。除此之外,在我看来,
for (;;)
比while (true)
更好。It looks like you are busy waiting, assuming a standard
BlockingQueue
. Usetake
instead ofpoll
.Other than that,
for (;;)
is nicer thanwhile (true)
, IMO.如果我做你正在谈论的事情,我会尝试这样做:
这可以让你确保你的消息队列上没有任何并发修改异常,以及当没有消息时你不会使用CPU时间while(true) 循环。现在您只需要确保当您向 messageQueue 添加某些内容时,您可以调用 lock.notifyAll() 以便线程知道再次运行。
If I were do what you are talking about I would try this:
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.