자바 ExecutorService 네 가지 스 레 드 탱크 사용 상세 설명

7948 단어 JavaExecutorService
1.머리말
스 레 드 탱크 를 합 리 적 으로 이용 하면 세 가지 좋 은 점 을 가 져 올 수 있다.첫째:자원 소 모 를 줄인다.만 든 스 레 드 를 반복 적 으로 이용 하여 스 레 드 생 성 과 소각 로 인 한 소 모 를 줄 입 니 다.둘째:응답 속 도 를 높 인 다.작업 이 도 착 했 을 때 작업 은 스 레 드 가 만들어 질 때 까지 기다 리 지 않 고 바로 수행 할 수 있 습 니 다.셋째,스 레 드 의 관리 성 을 향상 시킨다.스 레 드 는 희소 한 자원 이다.만약 에 무제 한 으로 만 들 면 시스템 자원 을 소모 할 뿐만 아니 라 시스템 의 안정성 도 낮 출 수 있다.스 레 드 탱크 를 사용 하면 통 일 된 분배,조정 과 감 시 를 할 수 있다.그러나 스 레 드 탱크 를 합 리 적 으로 이용 하려 면 그 원 리 를 손금 보 듯 잘 알 아야 한다.
2.스 레 드 탱크 사용
Executors 가 제공 하 는 네 가지 스 레 드 1.new CachedThreadPool 은 캐 시 스 레 드 풀 을 만 듭 니 다.스 레 드 풀 의 길이 가 처리 수 요 를 초과 하면 남 은 스 레 드 를 유연 하 게 회수 할 수 있 습 니 다.회수 할 수 없 으 면 새 스 레 드 를 만 듭 니 다.2.new Fixed ThreadPool 은 고정 라인 풀 을 만 들 고 스 레 드 의 최대 병발 수 를 제어 할 수 있 으 며 초과 한 스 레 드 는 대기 열 에서 기다 릴 수 있 습 니 다.3.new Scheduled ThreadPool 은 정기 적 이 고 주기 적 인 작업 수행 을 지원 하 는 고정 라인 풀 을 만 듭 니 다.4.new Single ThreadExecutor 는 단일 라인 화 된 스 레 드 풀 을 만 듭 니 다.유일한 작업 스 레 드 로 만 작업 을 수행 하고 모든 작업 이 지 정 된 순서(FIFO,LIFO,우선 순위)에 따라 실 행 될 수 있 도록 합 니 다.
1.new CachedThreadPool 은 캐 시 가능 한 스 레 드 풀 을 만 듭 니 다.스 레 드 풀 의 길이 가 처리 수 요 를 초과 하면 남 은 스 레 드 를 유연 하 게 회수 할 수 있 습 니 다.회수 할 수 없 으 면 새 스 레 드 를 만 듭 니 다.예 는 아래 와 같다.

ExecutorService executorService = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
  final int index = i;
  try {
    Thread.sleep(index * 1000);
  } catch (InterruptedException e) {
    e.printStackTrace();
  }
  executorService.execute(new Runnable() {
    @Override
    public void run() {
      System.out.println(Thread.currentThread().getName() + "," +index);
    }
  });
}
//     
pool-1-thread-1,0
pool-1-thread-1,1
pool-1-thread-1,2
pool-1-thread-1,3
pool-1-thread-1,4
2.new Fixed ThreadPool 은 고정 라인 풀 을 만 들 고 스 레 드 의 최대 병발 수 를 제어 할 수 있 으 며 초과 한 스 레 드 는 대기 열 에서 기다 릴 수 있 습 니 다.예 는 아래 와 같다.

ExecutorService fixedThreadPool = Executors.newFixedThreadPool(4);
for(int i=0;i<5;i++) {
  final int index = i;
    fixedThreadPool.execute(new Runnable() {
    @Override
    public void run() {
      try {
        System.out.println(Thread.currentThread().getName() + ", " + index);
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  });
}
//     
pool-1-thread-1,0
pool-1-thread-2,1
pool-1-thread-3,2
pool-1-thread-4,3
pool-1-thread-1,4
3.new Scheduled ThreadPool 은 정기 적 인 라인 풀 을 만 들 고 주기 와 정시 작업 예 시 는 다음 과 같 습 니 다.

ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
System.out.println("before:" + System.currentTimeMillis()/1000);
scheduledThreadPool.schedule(new Runnable() {
  @Override
  public void run() {
    System.out.println("  3      :" + System.currentTimeMillis()/1000);
  }
}, 3, TimeUnit.SECONDS);
System.out.println("after :" +System.currentTimeMillis()/1000);
//     
before:1518012703
after :1518012703
  3      :1518012706
System.out.println("before:" + System.currentTimeMillis()/1000);
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
  @Override
  public void run() {
    System.out.println("  1   ,3     :" +System.currentTimeMillis()/1000);
  }
}, 1, 3, TimeUnit.SECONDS);
System.out.println("after :" +System.currentTimeMillis()/1000);
콘 솔 메시지
before:1518013024
after :1518013024
1 초 지연 후 3 초 에 한 번 실행:1518013025
1 초 지연 후 3 초 에 한 번 실행:1518013028
1 초 지연 후 3 초 에 한 번 실행:1518013031
4.new Single ThreadExecutor 는 단일 라인 화 된 스 레 드 풀 을 만 들 고 작업 스 레 드 로 만 작업 을 수행 합 니 다.순 서 를 보장 합 니 다.예 를 들 어 다음 과 같 습 니 다.

ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i=0;i<10;i++) {
  final int index = i;
  singleThreadExecutor.execute(new Runnable() {
    @Override
    public void run() {
      try {
         System.out.println(Thread.currentThread().getName() + "," + index);
        Thread.sleep(2000);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  });
}
콘 솔 정보
pool-1-thread-1,0
pool-1-thread-1,1
pool-1-thread-1,2
pool-1-thread-1,3
pool-1-thread-1,4
스 레 드 풀 에 작업 을 제출 하 는 ThreadPoolExecutor 클래스 에서 execute()와 submit()의 구별 execute()방법 은 사실상 Executor 에서 설명 하 는 방법 으로 ThreadPoolExecutor 에서 구체 적 으로 실현 되 었 습 니 다.이 방법 은 ThreadPoolExecutor 의 핵심 방법 입 니 다.이 방법 을 통 해 스 레 드 풀 에 작업 을 제출 하고 스 레 드 풀 에 맡 길 수 있 습 니 다.
submit()방법 은 ExecutorService 에서 설명 하 는 방법 입 니 다.AbstractExecutorService 에서 구체 적 으로 실현 되 었 습 니 다.Thread PoolExecutor 에서 재 작성 하지 않 았 습 니 다.이 방법 도 스 레 드 탱크 에 임 무 를 제출 하 는 데 사 용 됩 니 다.그러나 execute()방법 과 달리 임 무 를 수행 한 결 과 를 되 돌려 주 고 소스 코드 를 통 해 submit()방법의 실현 을 볼 수 있 습 니 다.실제로 호출 된 execute()방법 인 것 을 발견 할 수 있 습 니 다.다만 Future 를 이용 하여 작업 수행 결 과 를 얻 었 을 뿐 입 니 다.

/**
 * @throws RejectedExecutionException {@inheritDoc}
 * @throws NullPointerException    {@inheritDoc}
 */
public Future<?> submit(Runnable task) {
  if (task == null) throw new NullPointerException();
  RunnableFuture<Void> ftask = newTaskFor(task, null);
  execute(ftask);
  return ftask;
}
스 레 드 탱크 의 닫 기 는 스 레 드 탱크 의 shutdown 이나 shutdown Now 방법 으로 스 레 드 탱크 를 닫 을 수 있 습 니 다.그러나 이들 의 실현 원 리 는 다 릅 니 다.shutdown 의 원 리 는 스 레 드 탱크 의 상 태 를 SHUTDOWN 상태 로 설정 한 다음 에 작업 을 수행 하고 있 지 않 은 모든 스 레 드 를 중단 하 는 것 입 니 다.shutdown Now 의 원 리 는 스 레 드 탱크 의 작업 스 레 드 를 옮 겨 다 니 며 스 레 드 의 interrupt 방법 으로 스 레 드 를 중단 하 는 것 입 니 다.따라서 중단 되 는 작업 에 응답 하지 못 하면 영원히 종료 할 수 없습니다.shutdown Now 는 먼저 스 레 드 탱크 의 상 태 를 STOP 로 설정 한 다음 작업 을 수행 하거나 중단 하 는 모든 스 레 드 를 중단 하고 작업 을 기다 리 는 목록 을 되 돌려 줍 니 다.
이 두 개의 닫 는 방법 중 하 나 를 호출 하면 isShutdown 방법 은 true 로 돌아 갑 니 다.모든 작업 이 닫 힌 후에 야 스 레 드 풀 이 닫 혔 음 을 표시 합 니 다.이 때 isTermined 방법 을 사용 하면 true 로 돌아 갑 니 다.스 레 드 풀 을 닫 기 위해 서 는 어떤 방법 을 사용 해 야 하 는 지 에 대해 서 는 스 레 드 풀 에 제출 된 작업 특성 에 의 해 결정 되 어야 합 니 다.보통 shutdown 을 사용 하여 스 레 드 풀 을 닫 습 니 다.작업 이 끝나 지 않 으 면 shutdown Now 를 호출 할 수 있 습 니 다.
3.  스 레 드 탱크 의 분석
프로 세 스 분석:스 레 드 탱크 의 주요 작업 절 차 는 다음 과 같다.자바 스 레 드 탱크 의 주요 작업 절차

위의 그림 에서 알 수 있 듯 이 새로운 작업 을 스 레 드 탱크 에 제출 할 때 스 레 드 탱크 의 처리 절 차 는 다음 과 같다.
4.567917.우선 스 레 드 탱크 는 기본 스 레 드 탱크 가 가득 찼 는 지 판단 합 니까?가득 차지 않 았 습 니 다.작업 스 레 드 를 만들어 서 작업 을 수행 합 니 다.가득 차 면 다음 절차 로 들어간다
  • 그 다음 에 스 레 드 탱크 는 작업 대기 열 이 가득 찼 는 지 판단 합 니까?가득 차지 않 으 면 새로 제출 한 작업 을 작업 대기 열 에 저장 합 니 다.가득 차 면 다음 절차 로 들어간다
  • 4.567917.마지막 스 레 드 탱크 는 전체 스 레 드 탱크 가 가득 찼 는 지 판단 합 니까?가득 차지 않 으 면 새로운 작업 스 레 드 를 만들어 임 무 를 수행 하고 가득 차 면 포화 전략 에 맡 깁 니 다**소스 코드 분석.**위의 절차 분석 은 우리 로 하여 금 직관 적 으로 이해 하 게 하 는 스 레 드 탱크 의 작업 원 리 를 다시 소스 코드 를 통 해 어떻게 실현 되 는 지 보 게 한다.스 레 드 탱크 에서 작업 을 수행 하 는 방법 은 다음 과 같 습 니 다.
    
    public void execute(Runnable command) {
      if (command == null)
        throw new NullPointerException();
      int c = ctl.get();
      if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
          return;
        c = ctl.get();
      }
      if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
          reject(command);
        else if (workerCountOf(recheck) == 0)
          addWorker(null, false);
      }
      else if (!addWorker(command, false))
        reject(command);
    }
    
    작업 라인.스 레 드 탱크 가 스 레 드 를 만 들 때 스 레 드 를 작업 스 레 드 Worker 로 밀봉 합 니 다.Worker 는 작업 을 수행 한 후에 작업 대기 열 에 있 는 작업 을 무한 순환 으로 가 져 옵 니 다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기