Java: Производитель / Потребитель, использующий BlockingQueue: потребительский поток ожидает (), пока другой объект не будет поставлен в очередь - PullRequest
0 голосов
/ 10 марта 2011

Недавно у меня возникли проблемы, связанные с потоками, с потребителем, который получает очки.Вот оригинал, который отлично работает, за исключением того, что он постоянно загружает процессор, проверяя очередь.Идея заключается в том, что 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 () каждый раз, когда вызывается функция cue, и снова работая с 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, будет продолжать ждать.

У меня было несколько идей, чтобы обойти это, в том числе сделать поток объектом и сделать так, чтобы он был уведомлен напрямую, ноЯ не был уверен, вызовет ли это больше проблем, чем исправит, будет очень плохим тоном или просто не сработает.Есть ли простое решение этой проблемы, которое мне не хватает?

Ответы [ 2 ]

11 голосов
/ 10 марта 2011

Смысл BlockingQueue в том, что вам не нужно самостоятельно писать этот код.

Просто вызовите take() вместо этого, который будет ждать, пока объект не будет вставлен в очередь, или используйте poll, но с таймаутом, чтобы он возвращал null только по истечении времени ожидания.

РЕДАКТИРОВАТЬ: просто чтобы уточнить ответ - как это в комментариях - это не только означает, что вы можете удалить код ожидания / уведомления; Вы также удаляете проверку размера, поскольку очередь делает это за вас.

3 голосов
/ 13 января 2012

Просто для добавления сказанного важно отметить разницу между put () и add ().Если ваша очередь заполнена, точки, которые вы пытаетесь вставить, могут фактически никогда не вставляться в очередь, потому что будет выдано исключение IllegalStateException, а put () будет ждать, если необходимо, чтобы вставить точку.

Документация дляadd () состояния

Добавляет указанный элемент в эту очередь, если это возможно сделать немедленно, возвращая true в случае успеха, иначе выдает исключение IllegalStateException.

в то время как положенные состояния

Добавляет указанный элемент в эту очередь, ожидая, если необходимо, чтобы освободилось место

...