2017-04-05 3 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

관련 문제