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

How to gracefully wait to job task finish in BlockingQueue java

我正在使用 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;
                }
        }
  }

如有任何改进建议,我们将不胜感激!

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

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

您不需要测试队列是否为空,您只需 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;
}