質問

Suppose I have BlockingQueue and some of the threads are called take() but the queue is empty at the moment. And suppose I somehow know that in the future new elements will not appear in the queue. How can I release those threads that are called take() from waiting? Thanks!

  public void run() {
        //noinspection InfiniteLoopStatement
        while (true) {
            try {
                Thread.sleep(millisecondsToSleep);
                if (!kitchen.processedOrdersEmpty()) {
                    Order processedOrder = kitchen.getFromProcessedOrders();
                    kitchen.printMessage("took order#" + processedOrder.getOrderNumber());
                    Thread.sleep(millisecondsToServe);
                    kitchen.printMessage("served order#" + processedOrder.getOrderNumber());
                } else {
                    int currentRandom = getNextRandom();
                    if (currentRandom <= 10) {
                        Order newOrder = new Order(kitchen.getLastOrderNumber());
                        kitchen.puIntoUnprocessedOrders(newOrder);
                        kitchen.printMessage("generated new order#" + newOrder.getOrderNumber());
                    } else {
                        Thread.sleep(millisecondsToSleep);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

where kitchen.getFromProcessedOrders() equals:

public Order getFromProcessedOrders() throws InterruptedException {
    return processedOrders.take();
} 

and processedOrders is a BlockingQueue

役に立ちましたか?

解決

According to java docs-

A BlockingQueue does not intrinsically support any kind of "close" or "shutdown" operation to indicate that no more items will be added. The needs and usage of such features tend to be implementation-dependent. For example, a common tactic is for producers to insert special end-of-stream or poison objects, that are interpreted accordingly when taken by consumers.

You should interrupt the thread where it is blocked -

public void run() {
        //noinspection InfiniteLoopStatement
        while (true) {
            try {
                Thread.sleep(millisecondsToSleep);
                if (!kitchen.processedOrdersEmpty()) {
                    Order processedOrder = kitchen.getFromProcessedOrders();
                    kitchen.printMessage("took order#" + processedOrder.getOrderNumber());
                    Thread.sleep(millisecondsToServe);
                    kitchen.printMessage("served order#" + processedOrder.getOrderNumber());
                } else {
                    int currentRandom = getNextRandom();
                    if (currentRandom <= 10) {
                        Order newOrder = new Order(kitchen.getLastOrderNumber());
                        kitchen.puIntoUnprocessedOrders(newOrder);
                        kitchen.printMessage("generated new order#" + newOrder.getOrderNumber());
                    } else {
                        Thread.sleep(millisecondsToSleep);
                    }
                }
            } catch (InterruptedException ex) { 
                //... handle ...
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

他のヒント

1) You can interrupt the thread where take() is running

2) You can put a special object to the queue as a signal of the end. If a thread gets a special object (END) it puts it back and exits, so other waiting threads will get END too.

You can add some dummy record like new String("##EOQ##") to signify End of Queue and stop consumer threads.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top