Java:使用 BlockingQueue 的生产者/消费者:让消费者线程 wait() 直到另一个对象排队
我最近遇到了一些与积分相关的消费者问题。这是原来的,除了占用大量CPU不断检查队列之外,它工作得很好。想法是cuePoint可以随便调用,主线程继续运行。
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class PointConsumer implements Runnable {
public static final int MAX_QUEUE_SIZE=500;
BlockingQueue<Point> queue;
public PointConsumer (){
this.queue=new ArrayBlockingQueue<Point>(MAX_QUEUE_SIZE);
}
public void cuePoint(Point p){
try{
this.queue.add(p);
}
catch(java.lang.IllegalStateException i){}
}
public void doFirstPoint(){
if(queue.size()!=0){
Point p=queue.poll();
//operation with p that will take a while
}
}
public void run() {
while(true){
doFirstPoint();
}
}
}
我试图通过每次调用提示函数时添加notify()来解决CPU问题,并将doFirstPoint()重新处理为如下所示:
public void doFirstPoint(){
if(queue.size()!=0){
//operation with p that will take a while
}
else{
try{
wait();
}
catch(InterruptedException ie){}
}
}
但是,我发现notify()和wait()仅在同步函数中工作。当我使doFirstPoint和cuePoint同步时,调用cuePoint的主线程将保持等待。
我有一些想法来解决这个问题,包括使线程成为一个对象并直接通知它,但我不确定这是否会导致比它能解决的问题更多的问题,形式非常糟糕,或者根本不起作用。对于我所缺少的这个问题有一个简单的解决方案吗?
I've been having some thread related problems recently with a consumer that takes points. Here is the original, which works fine except for taking up a lot of cpu constantly checking the queue. The idea is that cuePoint can be called casually and the main thread keeps going.
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
public class PointConsumer implements Runnable {
public static final int MAX_QUEUE_SIZE=500;
BlockingQueue<Point> queue;
public PointConsumer (){
this.queue=new ArrayBlockingQueue<Point>(MAX_QUEUE_SIZE);
}
public void cuePoint(Point p){
try{
this.queue.add(p);
}
catch(java.lang.IllegalStateException i){}
}
public void doFirstPoint(){
if(queue.size()!=0){
Point p=queue.poll();
//operation with p that will take a while
}
}
public void run() {
while(true){
doFirstPoint();
}
}
}
I tried to fix the cpu issue by adding notify() every time the cue function is called, and re-working doFirstPoint() to something like this:
public void doFirstPoint(){
if(queue.size()!=0){
//operation with p that will take a while
}
else{
try{
wait();
}
catch(InterruptedException ie){}
}
}
However, I found out that notify() and wait() only work in synchronized functions. When I make doFirstPoint and cuePoint synchronized, the main thread which has called cuePoint will be kept waiting.
I had a few ideas to get around this, including making the thread an object and having it be directly notified, but I wasn't sure if that would cause more problems than it would fix, be very bad form, or simply not work. Is there a simple solution to this problem that I'm missing?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
BlockingQueue
的要点是您不必自己编写此代码。只需调用
take()
即可,它将等待,直到将对象插入到队列中,或者使用poll
但有超时,以便它仅返回null
如果超时。编辑:只是为了澄清答案 - 正如评论中所述 - 这不仅意味着您可以删除等待/通知代码;而且还意味着您可以删除等待/通知代码。您还可以删除大小检查,因为队列会为您执行此操作。
The point of
BlockingQueue
is that you don't have to write this code yourself.Just call
take()
instead, which will wait until an object is inserted onto the queue, or usepoll
but with a timeout, so that it only returnsnull
if the timeout elapses.EDIT: Just to clarify the answer - as it's in the comments - not only does this mean you can remove the wait/notify code; you also remove the size check as the queue does that for you.
补充一下前面所说的,重要的是要注意 put() 和 add() 之间的区别。如果您的队列已满,您尝试插入的点实际上可能永远不会插入到队列中,因为将抛出 IllegalStateException,而 put() 将等待(如有必要)插入该点。
add() 状态的文档
while put 状态
Just to add on what's been said, it's important to note the difference between put() and add(). If your queue is full, points you try and insert may never actually be inserted in the queue, because an IllegalStateException will be thrown, while put() will wait, if necessary, to insert the point.
Documentation for add() states
while put states