스레드 풀 클래스 다이어그램
집행자 ==> ExcutorService ==> AbstractExecutorService ==> ThreadPoolExecutor입니다 분석합니다.
- URL 상속 계층 구조보다도 인터페이스의 최상위 스레드 풀 집행 인이 인터페이스는 하나의 메소드 무효 (Runnable를 명령)을 실행 가지고있다
- 집행 인 상속 ExecutorService입니다은 몇 가지 주요 새로운 방법 (Runnable를 (호출 가능)), 종료, shutdownNow의 등 제출
- 상기 방법 AbstractExecutorService 구현 여러 인터페이스 ExecutorService입니다.
- AbstractExecutorService 상속 가능한 ThreadPoolExecutor는 주요 방법 중 일부는 스레드 풀 (의 Runnable)을 실행 달성했다.
AbstractExecutorService
다음과 같이 AbstractExecutorService는 방법을 제출 달성 :
(호출 가능 작업) 제출 方法
- 공공 <T> 미래 <T> (호출 가능 <T> 작업) {제출
- (작업 == null가)) (새 NullPointerException이 던져;
- RunnableFuture <T> = ftask newTaskFor (작업);
- (ftask) 실행;
- ftask 반환;
- }
newTaskFor (호출 가능 호출) 方法
- 보호 <T> RunnableFuture <T> newTaskFor (호출 가능 <T> 호출) {
- 새로운 FutureTask <T>을 (호출)를 호출;
- }
FutureTask는 RunnableFuture 인터페이스를 실현 위는 RunnableFuture는 실행 가능한 및 미래의 인터페이스를 상속합니다. 무효 실행 만의 Runnable 인터페이스 방법, 미래의 인터페이스는 (부울) V get 및 (), V get 및 (긴 시간 초과 예외 : InterruptedException 장치), 부울의 isCancelled (), 부울의 isDone () 메소드를 취소 할 수 있습니다.
ThreadPoolExecutor입니다
그 후는 실행할 AbstractExecutorService.submit 메소드 호출 (ftask)에있어서, 이는 가능한 ThreadPoolExecutor를 실행하는 것이다. 그런 다음 우리는 시작 지점으로 방법을 실행하기 위해 분석해야합니다.
실행
- 공공 무효은 {(Runnable를 명령)를 실행할
- 경우 (명령 == NULL)
- () 새로운 NullPointerException이 던져;
- C = INT ctl.get ();
- 경우 (workerCountOf (c) <corePoolSize를) {
- 경우 (addWorker (명령, TRUE))
- 반환;
- C = ctl.get ();
- }
- 경우 (isRunning는 (c) && workQueue.offer (명령)) {
- INT 재확인 ctl.get = ();
- 만약 (! isRunning는 (재검) && 제거 (명령))
- (명령) 거부;
- 다른 경우 (workerCountOf (재검사) == 0)
- addWorker (NULL 거짓);
- }
- 다른 경우 (! addWorker (명령, 거짓))
- (명령) 거부;
- }
- 첫째, 적은 10보다, 작업이 성공적으로 반환됩니다 추가이 작업 (commadn를) 처리하는 작업자를 추가 할 경우 작업자 스레드의 현재 수는 적은 corePoolSize를보다 확인하십시오.
- 스레드가 실행 상태에 여전히, 그리고 작업이 성공적으로 큐에 추가 한 경우 비 실행 큐에서 작업을 삭제하면, 스레드 풀을 스레드 풀의 상태를 재 - 확인, 호출의 성공 거부, 여기 쓰레기는 정책에 따라 수행하는, 현재의 경우 작업자 스레드 수 (여기서주의 할 addWorker (NULL 거짓) 첫번째 파라미터와 동일하고 addWorker 상술하지 않음) 후, 작업자 추가 0
- 당신이 추가하면 작업자는 수행 방법을 거부하지 못합니다.
addWorker
- 개인 부울 addWorker (Runnable를 firstTask, 부울 코어) {
- 다시 해 보다:
- {(;;) 미국
- C = INT ctl.get ();
- RS = INT runStateOf (c);
- // 필요한 경우 큐는 비어 있는지 확인하십시오.
- 경우 (RS> = SHUTDOWN &&
- ! (RS == SHUTDOWN &&
- firstTask == 널 (null) &&
- ! workQueue.isEmpty ()))
- false를 반환;
- {(;;) 미국
- INT WC = workerCountOf (c);
- (화장실> = 용량 경우 ||
- WC> = (? corePoolSize를 코어 : maximumPoolSize를))
- false를 반환;
- 경우 (compareAndIncrementWorkerCount (c))
- 재 시도를 중단;
- C = ctl.get (); // 다시 읽어 CTL
- 경우 (runStateOf (C)! = RS)
- 재시도 계속;
- // 다른 CAS 인해 workerCount 변화에 실패; 내부 루프 재시
- }
- }
- 부울 workerStarted = 거짓;
- 부울 workerAdded = 거짓;
- 작업자 w = NULL;
- {시도
- w = 새 작업자 (firstTask);
- 마지막 스레드 t = w.thread;
- 경우 (t! = NULL) {
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- // 다시 확인 잠금을 보유하고있다.
- ThreadFactory를 실패하거나 경우 // 돌아 가기 밖으로
- // 잠금을 획득하기 전에 종료합니다.
- RS = INT runStateOf (ctl.get ());
- (RS <SHUTDOWN 경우 ||
- (RS == SHUTDOWN && firstTask == NULL)) {
- (t.isAlive ()) // PreCheck를 그 t IS 시작 가능한 경우
- () 새로운 예외 : IllegalThreadStateException을 던져;
- workers.add (w)는;
- S = INT workers.size ();
- 경우 (S> largestPoolSize)
- largestPoolSize의 = S;
- = 사실 workerAdded;
- }
- } 드디어 {
- mainLock.unlock ();
- }
- 경우 {(workerAdded)
- t.start ();
- workerStarted 사실 =;
- }
- }
- } 드디어 {
- 만약 (! workerStarted)
- (W)는 addWorkerFailed;
- }
- workerStarted를 반환;
- }
(1) 의사 결정 논리는 우리 첫번째보기, 더 복잡
- 경우 (RS> = SHUTDOWN &&
- ! (RS == SHUTDOWN &&
- firstTask == 널 (null) &&
- ! workQueue.isEmpty ()))
- false를 반환;
현재 상태가 SHUTDOWN보다 큰 경우, 판정 조건이 분명히 진짜야 직접 returnfalse 경우. 판단 조건이 거짓 인 경우 SHUTDOWN 이하의 현재 상태가, 다음, 아래로 이동하면 경우 (스레드 풀 RUNNING 상태가 잘 이해) (잘 이해, 스레드 풀은 새 작업자 A를 추가하지 확실히 닫혀) 동일의 현재 상태 SHUTDOWN : firstTask 큐 작업이 널 (null)에 해당하고 작업이있는 경우, 그것은 아래로 계속 실행 조건이 거짓 인 경우, 코드가 반환하지 않습니다 판단, null로 동일되지 않았거나 firstTask 작업 큐가 비어있는 경우,이 조건이 참 것으로 판단, false를 돌려줍니다 합니다 (처음 널 (null)와 같은 경우는 예 하오는, 따라서. 우리는 스레드 풀은 더 이상 새 작업을 수락 종료 상태를 알 수 없지만, 작업은 작업 대기열 또는 작업을 완료 할 수있다, 이것을 이해하고 작업 큐는 작업을 가지고 있지만, 또한 계속 규정. 반대의 경우, (2) 작업자 스레드의 현재 수를 결정하기 위해) 내려 가지 않을 것이다
- {(;;) 미국
- INT WC = workerCountOf (c);
- (화장실> = 용량 경우 ||
- WC> = (? corePoolSize를 코어 : maximumPoolSize를))
- false를 반환;
- 경우 (compareAndIncrementWorkerCount (c))
- 재 시도를 중단;
- C = ctl.get (); // 다시 읽어 CTL
- 경우 (runStateOf (C)! = RS)
- 재시도 계속;
- // 다른 CAS 인해 workerCount 변화에 실패; 내부 루프 재시
- }
작업자 스레드의 현재 수는 제한 매개 변수는 스레드 풀 설정, 작업자를 추가하는 CAS의 사용을 초과하지 않으며, 루프 외부에서 아래로 계속 실행합니다. 그렇지 않으면 false를 반환, 근로자가 실패 추가합니다. (3) 상기 단계 (12)의 종료 후 수행 새로운 작업자 (firstTask)는 t가 w.thread 스레드 풀을 나사산 유효한 경우, 현재 작업 스레드 풀 작업자 HashSet의 실행한다 t에 첨가하고, 다시 한번 상태를 체크 .start. 작업을 수행하기 위해 하위 스레드를 열기 전에이 시간.
하위 스레드 실행 방법
통화 t.start 위의 3 단계, 실행 방법은 노동자에 실행하는 하위 스레드를 엽니 다.
- 공공 무효 실행 () {
- runWorker (이);
- }
- 최종 공극 runWorker (w 작업자) {
- () 스레드는 Thread.currentThread 중량 =;
- 실행 가능한 작업은 w.firstTask를 =;
- w.firstTask = NULL;
- () w.unlock; // 수 있도록 인터럽트
- 부울 completedAbruptly 사실 =;
- {시도
- 동안 (작업! = null의 || (작업 =를 getTask ())! = NULL) {
- () w.lock;
- // 풀 스레드를 확인 중지되면은 중단;
- //하지 않을 경우, 확인 스레드가 중단되지 않습니다. 이
- // 거래에 대한 두 번째 경우의 재 점검과 함께이 필요
- // shutdownNow의 레이스 동안 청소 인터럽트
- 경우 ((runStateAtLeast (ctl.get (), STOP) ||
- (Thread.interrupted () &&
- runStateAtLeast (ctl.get (), STOP))) &&
- ! wt.isInterrupted ())
- wt.interrupt ();
- {시도
- beforeExecute (중량, 작업);
- Throwable를 던져 = NULL;
- {시도
- task.run ();
- }드디어 {
- afterExecute (작업, 던져);
- }
- } 드디어 {
- 작업 = NULL;
- w.completedTasks ++;
- () w.unlock;
- }
- }
- completedAbruptly = FALSE;
- } 드디어 {
- processWorkerExit (completedAbruptly, w);
- }
- }
지속적를 getTask () 메소드,이 Workqueue에서 인수 작업을 통해 노동자보다도, 어떤 작업을 취득하지 않은 경우, processWorkerExit 메서드가 호출됩니다.
를 getTask ()
- 개인의 Runnable를 getTask () {
- 부울 TIMEDOUT = 거짓; // 마지막 여론 조사 () 시간 제한을 했습니까?
- {(;;) 미국
- C = INT ctl.get ();
- RS = INT runStateOf (c);
- // 필요한 경우 큐는 비어 있는지 확인하십시오.
- 경우 (RS> = SHUTDOWN && (RS> = STOP || workQueue.isEmpty ())) {
- decrementWorkerCount ();
- NULL을 반환;
- }
- INT WC = workerCountOf (c);
- // 컬링 근로자 대상이 있습니까?
- 부울 타이밍 된 allowCoreThreadTimeOut = || WC> corePoolSize를;
- 경우 ((WC> maximumPoolSize를 || (타이밍 된 && TIMEDOUT))
- && (WC> 1 || workQueue.isEmpty ())) {
- 경우 (compareAndDecrementWorkerCount (c))
- NULL을 반환;
- 계속하다;
- }
- {시도
- 실행 가능한 R = 타임?
- workQueue.poll (이 KeepAliveTime, TimeUnit.NANOSECONDS) :
- workQueue.take ();
- 경우 (R! = null이)
- R를 반환;
- TIMEDOUT 사실 =;
- } 캐치 (예외 : InterruptedException 재시도) {
- TIMEDOUT = 거짓;
- }
- }
- }
를 getTask 무한 루프 방법하는 방법으로서, 먼저 스레드 풀의 현재 상태를 결정
- 경우 (RS> = SHUTDOWN && (RS> = STOP || workQueue.isEmpty ())) {
- decrementWorkerCount ();
- NULL을 반환;
- }
이 판단은 물론 RS == 종료,이 Workqueue이 비어있는 경우, 분명히 직접 널 (null)을 반환해야하고, 작업에 앞서 하나의 작업자에 의해 감소, 이해된다. (를 getTask 복귀 널은 runWorker 방법은 HashSet의 작업자로부터 processWorkerExit 삭제 전류를 호출한다), 그렇지 않으면 스레드 풀에서 설명한 상기 SHUTDOWN보다 RS> 크다 (이 방법은 작업 큐에 대기하는 태스크가 실행되지는 shutdownNow의 스레드 풀에 대응하는) 경우 실행, 아래로 계속 실행됩니다. 그런 다음 스레드 스레드 풀은 현재 설정하고, 시간이 지남에 따라 허용 여부 및 상태 표시 줄 coreThread이 Workqueue 결정의 최대 수를 함께 스레드의 CAS 번호 저장는 null에 의해 작동 여부. 마지막으로, 우리는 작업 큐 세 헤드 작업에서 다음 작업에 관심을 얻기 위해 싶습니다.
- 실행 가능한 R = 타임?
- workQueue.poll (이 KeepAliveTime, TimeUnit.NANOSECONDS) :
- workQueue.take ();
진짜야에 시간이 초과하면 대기 시간이 아직 덜, 현재 노동자도 회수 할 수있다 workerCount corePoolSize를보다가 발생할 수도이 때,이 Workqueue R = 널에서 작업을 달성하지 않은 것보다 더 (allowCoreThreadTimeOut true로 설정)합니다. 시간 제한 거짓이 방법을 차단 호출이 Workqueue에서 작업을 얻을 경우, 인 newFixedThreadPool 항상이 Workqueue가 비어있는 경우에도 폐쇄 스레드 풀을 표시하지 않고 달성 할 수 있도록 같이 차단 메소드를 호출뿐만 아니라 작업자 스레드의 고정 된 수를 유지하기 위해 .
shutDown (shutDownNow) 방법
- 공개 목록 <Runnable를> shutdownNow의 () {
- 목록 <Runnable를> 작업;
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- checkShutdownAccess ();
- SHUTDOWN로 // shutDwonNow STOP으로 셧다운
- advanceRunState (STOP) (advanceRunState (SHUTDOWN))
- interruptWorkers () (interruptIdleWorkers)
- // shutdownNow의 특수
- 태스크 drainQueue = ();
- // shutDown에 특별 스케줄 할 콜백
- () onShutdown;
- } 드디어 {
- mainLock.unlock ();
- }
- tryTerminate ();
- 작업을 반환;
- }
셧다운 shutDownnNow 차분 법 (코드 레벨)
- shutdownNow의 : advanceRunState (STOP), interruptWorkers의 셧다운 advanceRunState (종료), interruptIdleWorkers
- shutDown에 더 onShutdown ();로 스케줄 onShutDown 복제하는 방법.
- shutdownNow의 방법은 큐되지 않은 작업을 작동합니다.
- interruptIdleWorkers
interruptIdleWorkers 与 interruptWorkers
(1) shutdownNow의
- 개인 무효 interruptWorkers () {
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- 대한 (노동자 w : 노동자)
- () w.interruptIfStarted;
- } 드디어 {
- mainLock.unlock ();
- }
- }
분명히, 이것은 중단 모든 스레드 (2) 종료입니다
- 개인 무효 interruptIdleWorkers (부울 onlyOne) {
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- 대한 (노동자 w : 노동자) {
- t = w.thread 스레드;
- 만약 (! t.isInterrupted () && w.tryLock ()) {
- {시도
- t.interrupt ();
- } 캐치 (SecurityException가 무시) {
- } 드디어 {
- () w.unlock;
- }
- }
- 경우 (onlyOne)
- 단절;
- }
- } 드디어 {
- mainLock.unlock ();
- }
- }
참고 onlyOne 매개 변수,이 때문에 종료 방법을 위해, 단지 내부 호출 (TRUE) tryTerminate () 메서드 호출의 interruptIdleWorkers, 다른 경우는 interruptIdleWorkers (false)를하다에,뿐만 아니라 모든되지 않았습니다 중단 된 스레드를 중단하려고합니다. 이 방법은 그 다음에 (2)에서 전술 한 3) tryTerminate tryTerminate 방법 모양
- 최종 공극 tryTerminate () {
- {(;;) 미국
- C = INT ctl.get ();
- 경우 (isRunning는 (C) ||
- runStateAtLeast (C, 정리) ||
- (runStateOf (c) == SHUTDOWN &&! workQueue.isEmpty ()))
- 반환;
- 경우을 (workerCountOf (C)! = 0) {대상 종료합니다 //
- interruptIdleWorkers (ONLY_ONE);
- 반환;
- }
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- 경우 (ctl.compareAndSet (c, ctlOf (정리, 0))) {
- {시도
- () 종료;
- } 드디어 {
- ctl.set (ctlOf (TERMINATED, 0));
- termination.signalAll ();
- }
- 반환;
- }
- } 드디어 {
- mainLock.unlock ();
- }
- 실패 CAS에 // 다른 재시도
- }
- }
위의 코드에서 볼 수 있듯이 작업자 스레드 수는 스레드 풀의 상태가 SHUTDOWN 경우, 비어있는,이 Workqueue 스레드 풀은 0 또는 정지 상태, 작업자 스레드 0의 수, 스레드 풀은 결국 TERMINATED 상태로 있고, 모든 깨어 것 termination.awaitNanos (나노)의 호출 awaitTermination () 메소드 블록 스레드를 깨워하지 않은 때문이다.
- 공공 부울 awaitTermination (긴 시간 초과 예외 : InterruptedException 단위)
- 던져 예외 : InterruptedException {
- 긴 나노 = unit.toNanos (초과);
- 최종 ReentrantLock와 mainLock = this.mainLock;
- mainLock.lock ();
- {시도
- {(;;) 미국
- 경우 (runStateAtLeast (ctl.get (), TERMINATED))
- true를 반환;
- 만약 (나노 <= 0)
- false를 반환;
- 나노 = termination.awaitNanos (나노);
- }
- } 드디어 {
- mainLock.unlock ();
- }
- }
방법은 위의 TryTerminate, addWorkerFailed (), processWorkerExit () 셧다운 (), shutdownNow의 (), 제거 (Runnable를 작업) 방법으로 호출됩니다.
스레드 풀을 설명하기 5 주
스레드 풀의 위에서 언급 한 자주 실행 상태, 여기에 대한 간략한 설명.
- 개인 정적 최종 INT 실행 = -1 << COUNT_BITS;
- 개인 정적 최종 INT의 SHUTDOWN = 0 << COUNT_BITS;
- 개인 정적 최종 INT의 STOP = 1 << COUNT_BITS;
- 개인 정적 최종 INT의 정리 = 2 << COUNT_BITS;
- 개인 정적 최종 INT는 = 3 << COUNT_BITS 말단;
국가의 정의
- RUNNING : 새로운 작업이 Workqueue에서 처리 작업.
- SHUTDOWN : 새 작업을 허용하지 않습니다,하지만 작업을 완료하는 데 계속이 Workqueue
- STOP은 : Workqueue는 미완성 작업을 처리하지 않는 새 작업을 허용하지 않습니다, 실행중인 모든 작업을 중단하려고
- 정리 : 모든 작업이 완료되었습니다 작업자 스레드의 수는 0, 스레드 풀의 상태는 정리 () 메소드를 종료 호출 될 것입니다.
- TERMINATED : 종료 () 메소드가 완료되었습니다
다섯 개 상태 변환
- RUNNING -> SHUTDOWN 다음 마무리 아마도 암시 통화 종료 () 메소드 () 메서드
- (RUNNING 또는 종료) -> STOP : 전화 shutdownNow의 () 메소드
- SHUTDOWN -> 정리 : Workqueue는 수영장 비어 있습니다
- STOP -> 정리가 : 풀 비어
- 정리 -> 종료되었습니다 : 方法) (종료 完成