Java:使用 BlockingQueue 的生产者/消费者:让消费者线程 wait() 直到另一个对象排队

发布于 2024-10-21 03:24:07 字数 1414 浏览 0 评论 0原文

我最近遇到了一些与积分相关的消费者问题。这是原来的,除了占用大量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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

虫児飞 2024-10-28 03:24:07

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 use poll but with a timeout, so that it only returns null 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.

本宫微胖 2024-10-28 03:24:07

补充一下前面所说的,重要的是要注意 put() 和 add() 之间的区别。如果您的队列已满,您尝试插入的点实际上可能永远不会插入到队列中,因为将抛出 IllegalStateException,而 put() 将等待(如有必要)插入该点。

add() 状态的文档

如果可能的话,将指定元素添加到此队列中
立即,成功后返回 true,否则抛出
IllegalStateException。

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

Adds the specified element to this queue if it is possible to do so
immediately, returning true upon success, else throwing an
IllegalStateException.

while put states

Adds the specified element to this queue, waiting if necessary for
space to become available

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文