Thread PoolExecutor 의 work Queue 를 가득 채 울 때 submit()방법 을 자동 으로 차단 합 니 다.

10500 단어 eclipse 개인 소감
자바 의 Thread PoolExecutor 를 사용 하면 일부 작업 을 동시에 수행 할 수 있 습 니 다.기본 적 인 용법 은:
(1)
만 들 기 ThreadPoolExecutor 대상
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(workQueueSize));

여기 서 사용 하 는 구조 함 수 는:
/**
 * Creates a new <tt>ThreadPoolExecutortt> with the given initial
 * parameters and default thread factory and rejected execution handler.
 * It may be more convenient to use one of the {@link Executors} factory
 * methods instead of this general purpose constructor.
 *
 * @param corePoolSize the number of threads to keep in the
 * pool, even if they are idle.
 * @param maximumPoolSize the maximum number of threads to allow in the
 * pool.
 * @param keepAliveTime when the number of threads is greater than
 * the core, this is the maximum time that excess idle threads
 * will wait for new tasks before terminating.
 * @param unit the time unit for the keepAliveTime
 * argument.
 * @param workQueue the queue to use for holding tasks before they
 * are executed. This queue will hold only the <tt>Runnablett>
 * tasks submitted by the <tt>executett> method.
 */
public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue) {
    this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
         Executors.defaultThreadFactory(), defaultHandler);
}

간단명료 하 게 설명 하 다.
첫 번 째 매개 변수 corePoolSize 온라인 스 레 드 탱크 의 스 레 드 수 를 유지 하 는 것 입 니 다.이 스 레 드 가 비어 있 더 라 도 계속 남아 있 습 니 다.
두 번 째 매개 변수 maximumPoolSize 는 스 레 드 탱크 에서 가장 허용 되 는 스 레 드 수 입 니 다.
마지막 매개 변수 work Queue 는 실행 전의 task,즉 task 를 저장 하 는 데 사 용 됩 니 다. work Queue 에서 끊임없이 꺼 내 서 스 레 드 탱크 에 넣 고 실행 합 니 다.
글 의 출처: http://www.codelast.com/
(2)
만 든 Thread PoolExecutor 대상,필요 한 곳 에서 끊임없이 퀘 스 트 제출(submit)
executor.submit(new MyTask());

그 중에서 MyTask 는 사용자 정의 클래스 입 니 다.예 를 들 어:
public class MyTask implements Runnable {
  @Override
  public void run() {
    //TODO:
  }
}

우 리 는 run()방법 에 구체 적 인 임 무 를 수행 하 는 코드 를 써 야 한다.
글 의 출처: http://www.codelast.com/
워 크 큐 의 크기 가 제한 되 어 있 기 때문에 submit()작업 이 너무 빠 를 때(즉,task 가 워 크 큐 의 모든 공간 을 차지 하고 있 습 니 다.이때 새로운 task 가 제출 되 어야 합 니 다)새로운 task 를 워 크 큐 에 넣 을 수 없 게 될 것 입 니 다.이때 submit()방법 은 이상 을 던 져"더 이상 견 딜 수 없습니다.임 무 를 천천히 배정 해 주세요"라 고 밝 혔 습 니 다.
이것 은 일부 응용 장면 에서 OK 이다.예 를 들 어 웹 페이지 를 캡 처 하 는 시스템(파충류)에서 웹 페이지 를 캡 처 하 는 task 를 제출 하 는 것 은 순간 적 인 일이 고 웹 페이지 캡 처 과정 은 속도 병목 이 될 수 있 기 때문에 이 시스템 의 부하 가 매우 높다 면 우 리 는 일부 URL 을 포기 하고 캡 처 하지 않 을 수도 있 고 시스템 이 끊임없이 수많은 URL 을 쌓 아 서 는 안 된다.시스템 이 결국 무 너 지게 만 들 었 다.
그러나 다른 응용 장면 에서 이것 은 받 아들 일 수 없다.왜냐하면 우 리 는 시스템 의 처리 속도 가 느리다 고 해서 우리 가 반드시 실행 해 야 할 task 를 버 릴 수 없 기 때문이다.왜냐하면 이런 task 는 매우 중요 하기 때문에 시간 을 좀 더 써 서 시스템 을 천천히 처리 하 더 라 도 하나의 task 를 손실 해 서 는 안 된다.한 마디 로 하면,"기다 릴 수 있다",그러나"잃 어 버 릴 수 없다".
글 의 출처: http://www.codelast.com/
그래서 문제 가 생 겼 습 니 다.어떻게 Thread PoolExecutor 의 work Queue 가 가득 찬 상황 에서 submit()방법 을 블록 할 수 있 습 니까?자원 이 있 을 때 까지 기 다 렸 다가 task 를 계속 제출 할 수 있 습 니까?
유사 한 효 과 를 실현 할 수 있 는 여러 가지 방법 이 있다.
「1」 Thread PoolExecutor 로 하여 금 자신 이 실현 한 Rejected Execution Handler 를 사용 하 게 하고,그 중에서 task 를 work Queue 에 차단 식 으로 넣 습 니 다.
이것 은 인터넷 에서 많은 튜 토리 얼 이 제공 하 는 방법 이다.
그래서 우선 Rejected Execution Handler 가 어떤 귀신 인지,Thread PoolExecutor 와 무슨 관계 가 있 는 지 말씀 드 리 겠 습 니 다.
Thread PoolExecutor 는"거부 정책"을 설정 할 수 있 습 니 다.이것 은 task 가 스 레 드 탱크 에 추가 되 는 것 을 거부 할 때 취 하 는 처리 조 치 를 말 합 니 다.예 를 들 어:
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());

이 때문에 task 가 스 레 드 탱크 에 추가 되 는 것 을 거부 할 때 Thread PoolExecutor 는 이 작업 을'버 리 기'정책 으로 처리 합 니 다.즉,이 task 가 버 려 졌 습 니 다.
그렇다면 어떻게 Rejected Execution Handler 를 이용 하여 submit()를 막 습 니까?
우선 submit()방법 은 work Queue 의 offer()방법 을 호출 하여 task 를 입력 하 는 것 입 니 다.offer()방법 은 차단 되 지 않 습 니 다.work Queue 가 가득 찼 을 때 offer()방법 은 즉시 false 로 돌아 갑 니 다.그곳 에서 work Queue 가 빈 자리 가 있 기 를 기다 리 는 것 을 막 지 않 기 때문에 submit()를 막 아야 합 니 다.관건 은 work Queue 에 task 를 추가 하 는 행 위 를 바 꾸 는 것 입 니 다.따라서...이런 방법 이 있다.
executor.setRejectedExecutionHandler(new RejectedExecutionHandler() {
  @Override
  public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    if (!executor.isShutdown()) {
      try {
        executor.getQueue().put(r);
      } catch (InterruptedException e) {
      }
    }
  }
});

그 중에서 재 작성 한 rejected Execution()방법 은 getQueue()방법 을 호출 하여 work Queue 를 얻 었 고 put()방법 을 호출 하여 task 를 work Queue 에 넣 었 습 니 다.이 put()방법 은 막 혔 습 니 다.
/**
* Inserts the specified element into this queue, waiting if necessary for space to become available.
*/
void put(E e) throws InterruptedException;

이것 은 원 하 는 효 과 를 얻 었 습 니 다.work Queue 가 가득 찼 을 때 submit()하나의 task 는 사용자 정의 Rejected Execution Handler 를 호출 할 수 있 습 니 다.사용자 정의 Rejected Execution Handler 는 이 task 가 계속 차단 식 put()를 work Queue 에 사용 하도록 보장 합 니 다.
글 의 출처: http://www.codelast.com/
비록 이런 방법 은 매우 간단 하지만 그것 을 사용 하 는 것 은 매우 좋 지 않다.원인 은 다음 과 같다.
[1] 
Thread PoolExecutor 의 API 는 이렇게 하 는 것 을 권장 하지 않 습 니 다.
/**
 * Returns the task queue used by this executor. Access to the
 * task queue is intended primarily for debugging and monitoring.
 * This queue may be in active use.  Retrieving the task queue
 * does not prevent queued tasks from executing.
 *
 * @return the task queue
 */
public BlockingQueue getQueue() {
    return workQueue;
}

이 를 통 해 알 수 있 듯 이 API 는 getQueue()는 주로 디 버 깅 과 모니터링 에 사용 된다.
[2] 자물쇠 등 을 초래 할 수 있 습 니 다.(자세히 연구 하지 않 음)
글 의 출처: http://www.codelast.com/
「2」
CallerRunsPolicy 사용 하기
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

이러한 거부 정책 을 사용 할 때 워 크 큐 가 가득 차 면 Thread PoolExecutor 는 호출 자 스 레 드(즉 생산자 스 레 드)에서 제출 할 task-생산자 스 레 드 가 소비자 스 레 드 를 도와'하지 말 아야 할 일'을 수행 합 니 다.
이런 방법 을 사용 할 때 생산자 스 레 드 는 task 가 실 행 될 때 까지 새로운 task 를 제출 하지 못 할 것 이다.그 밖 에 다른 문제 가 없 는 것 같다.느낌 이 좀 이상 하 다 는 것 을 제외 하고 생산자 스 레 드 는 한 사람 이 두 캐릭터 를 연기 하기 때문이다.
글 의 출처: http://www.codelast.com/
「3」 자신 이 offer()방법 을 다시 쓴 BlockingQueue
submit()는 work Queue 의 offer()방법 을 호출 하여 task 를 추가 하 는 것 이 고,offer()는 차단 되 지 않 기 때문에,만약 우리 가 하나의 BlockingQueue 를 실현 한다 면,offer()방법 이 차단 된다 면,그것 은 Thread PoolExecutor 와 협조 하여 submit()방법 이 work Queue 가 가득 찼 을 때의 차단 효 과 를 실현 할 수 있 습 니 다. StackOverflow ):
public class LimitedQueue<E> extends LinkedBlockingQueue<E> {
  public LimitedQueue(int maxSize) {
    super(maxSize);
  }

  @Override
  public boolean offer(E e) {
    // turn offer() and add() into a blocking calls (unless interrupted)
    try {
      put(e);
      return true;
    } catch (InterruptedException ie) {
      Thread.currentThread().interrupt();
    }
    return false;
  }
}

그리고 Thread PoolExecutor 대상 을 구성 할 때 마지막 매개 변수 인 work Queue 는 이 Limited Queue 류 의 대상 을 사용 하면 됩 니 다.

좋은 웹페이지 즐겨찾기