2017-04-05 9 views
0

BlockingQueueとExecutorServiceを使用してジョブキューを作成しています。基本的にキュー内の新しいデータを待っています。キューにデータがあれば、executorServiceはキューからデータを取得します。しかし、問題は、ループを使用してキューにデータがあることを待ち、CPU使用率が非常に高いことです。 このapiを使用するのは初めてです。これを改善する方法がわからないBlockingQueueで正常に仕事を終了する方法java

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; 
       } 
     } 
    } 

これを改善する方法についてのご意見をお待ちしております。

+0

あなたのタイトルは、あなたの質問に同意しません。 – EJP

答えて

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; 
} 
1
 if (mBlockingQueue.isEmpty()) { 
      mQueueState = PollingQueueState.WAITING; 
     } else { 
      mQueueState = PollingQueueState.FETCHING; 
     } 
     if (mQueueState == PollingQueueState.FETCHING) 

これらの行、break;、および対応する閉じ中括弧を削除します。

+0

NB 'mQueueState'変数は必要ありません。上記のロジックを使用して、いつでもキューサイズから直接推測できます。 – EJP

+0

申し訳ありませんが、私は最初の答えを見ていない、あなたの答えもあまりにも動作します。私は考えを持って、take()メソッドは、キューからデータをフェッチするまでスレッドをブロックします – Cheng

関連する問題