如何在BlockingQueue java中优雅地等待工作任务完成

时间:2017-04-05 22:40:47

标签: java executorservice blockingqueue

我正在使用BlockingQueue和ExecutorService编写一个作业队列。它基本上等待队列中的新数据,如果有任何数据放入队列,executorService将从队列中获取数据。但问题是我使用的循环循环等待队列拥有数据,因此CPU使用率非常高。 我是新手使用这个api。不知道如何改善这一点。

ExecutorService mExecutorService = Executors.newSingleThreadExecutor();
BlockingQueue<T> mBlockingQueue = new ArrayBlockingQueue();

public void handleRequests() {
       Future<T> future = mExecutorService.submit(new WorkerHandler(mBlockingQueue, mQueueState));
        try {
              value = future.get();
        } catch (InterruptedException | ExecutionException e) {
              e.printStackTrace();
        }
        if (mListener != null && returnedValue != null) {
              mListener.onNewItemDequeued(value);
        }
     }
}

private static class WorkerHandler<T> implements Callable<T> {

    private final BlockingQueue<T> mBlockingQueue;
    private PollingQueueState mQueueState;

    PollingRequestHandler(BlockingQueue<T> blockingQueue, PollingQueueState state) {
        mBlockingQueue = blockingQueue;
        mQueueState = state;
    }

    @Override
    public T call() throws Exception {
        T value = null;
        while (true) {   // problem is here, this loop takes full cpu usage if queue is empty
            if (mBlockingQueue.isEmpty()) {
                mQueueState = PollingQueueState.WAITING;
            } else {
                mQueueState = PollingQueueState.FETCHING;
            }
            if (mQueueState == PollingQueueState.FETCHING) {
                try {
                    value = mBlockingQueue.take();
                    break;
                } catch (InterruptedException e) {
                    Log.e(TAG, e.getMessage(), e);
                    break;
                }
        }
  }

非常感谢任何有关如何改善这一点的建议!

2 个答案:

答案 0 :(得分:1)

        if (mBlockingQueue.isEmpty()) {
            mQueueState = PollingQueueState.WAITING;
        } else {
            mQueueState = PollingQueueState.FETCHING;
        }
        if (mQueueState == PollingQueueState.FETCHING)

删除这些行,break;和匹配的右括号。

答案 1 :(得分:1)

您不需要测试队列为空,只需要take(),因此线程会阻塞,直到数据可用。

当一个元素被放入队列时,线程唤醒一个值被设置。

如果您不需要取消刚才需要的任务:

@Override
public T call() throws Exception {
    T value = mBlockingQueue.take();
    return value;
}

如果您想取消任务:

@Override
public T call() throws Exception {
    T value = null;
    while (value==null) {   
            try {
                value = mBlockingQueue.poll(50L,TimeUnit.MILLISECONDS);
                break;
            } catch (InterruptedException e) {
                Log.e(TAG, e.getMessage(), e);
                break;
            }
    }
    return value;
}