기본 스레드 풀의 인터뷰 분석

스레드 풀 클래스 다이어그램

집행자 ==> ExcutorService ==> AbstractExecutorService ==> ThreadPoolExecutor입니다 분석합니다.

 

  • URL 상속 계층 구조보다도 인터페이스의 최상위 스레드 풀 집행 인이 인터페이스는 하나의 메소드 무효 (Runnable를 명령)을 실행 가지고있다
  • 집행 인 상속 ExecutorService입니다은 몇 가지 주요 새로운 방법 (Runnable를 (호출 가능)), 종료, shutdownNow의 등 제출
  • 상기 방법 AbstractExecutorService 구현 여러 인터페이스 ExecutorService입니다.
  • AbstractExecutorService 상속 가능한 ThreadPoolExecutor는 주요 방법 중 일부는 스레드 풀 (의 Runnable)을 실행 달성했다.

 

AbstractExecutorService

다음과 같이 AbstractExecutorService는 방법을 제출 달성 :

(호출 가능 작업) 제출 方法

  1. 공공 <T> 미래 <T> (호출 가능 <T> 작업) {제출
  2. (작업 == null가)) (새 NullPointerException이 던져;
  3. RunnableFuture <T> = ftask newTaskFor (작업);
  4. (ftask) 실행;
  5. ftask 반환;
  6. }

newTaskFor (호출 가능 호출) 方法

  1. 보호 <T> RunnableFuture <T> newTaskFor (호출 가능 <T> 호출) {
  2. 새로운 FutureTask <T>을 (호출)를 호출;
  3. }

FutureTask는 RunnableFuture 인터페이스를 실현 위는 RunnableFuture는 실행 가능한 및 미래의 인터페이스를 상속합니다. 무효 실행 만의 Runnable 인터페이스 방법, 미래의 인터페이스는 (부울) V get 및 (), V get 및 (긴 시간 초과 예외 : InterruptedException 장치), 부울의 isCancelled (), 부울의 isDone () 메소드를 취소 할 수 있습니다.

ThreadPoolExecutor입니다

그 후는 실행할 AbstractExecutorService.submit 메소드 호출 (ftask)에있어서, 이는 가능한 ThreadPoolExecutor를 실행하는 것이다. 그런 다음 우리는 시작 지점으로 방법을 실행하기 위해 분석해야합니다.

실행

  1. 공공 무효은 {(Runnable를 명령)를 실행할
  2. 경우 (명령 == NULL)
  3. () 새로운 NullPointerException이 던져;
  4. C = INT ctl.get ();
  5. 경우 (workerCountOf (c) <corePoolSize를) {
  6. 경우 (addWorker (명령, TRUE))
  7. 반환;
  8. C = ctl.get ();
  9. }
  10. 경우 (isRunning는 (c) && workQueue.offer (명령)) {
  11. INT 재확인 ctl.get = ();
  12. 만약 (! isRunning는 (재검) && 제거 (명령))
  13. (명령) 거부;
  14. 다른 경우 (workerCountOf (재검사) == 0)
  15. addWorker (NULL 거짓);
  16. }
  17. 다른 경우 (! addWorker (명령, 거짓))
  18. (명령) 거부;
  19. }
  • 첫째, 적은 10보다, 작업이 성공적으로 반환됩니다 추가이 작업 (commadn를) 처리하는 작업자를 추가 할 경우 작업자 스레드의 현재 수는 적은 corePoolSize를보다 확인하십시오.
  • 스레드가 실행 상태에 여전히, 그리고 작업이 성공적으로 큐에 추가 한 경우 비 실행 큐에서 작업을 삭제하면, 스레드 풀을 스레드 풀의 상태를 재 - 확인, 호출의 성공 거부, 여기 쓰레기는 정책에 따라 수행하는, 현재의 경우 작업자 스레드 수 (여기서주의 할 addWorker (NULL 거짓) 첫번째 파라미터와 동일하고 addWorker 상술하지 않음) 후, 작업자 추가 0
  • 당신이 추가하면 작업자는 수행 방법을 거부하지 못합니다.

 

addWorker

 

  1. 개인 부울 addWorker (Runnable를 firstTask, 부울 코어) {
  2. 다시 해 보다:
  3. {(;;) 미국
  4. C = INT ctl.get ();
  5. RS = INT runStateOf (c);
  6.  
  7. // 필요한 경우 큐는 비어 있는지 확인하십시오.
  8. 경우 (RS> = SHUTDOWN &&
  9. ! (RS == SHUTDOWN &&
  10. firstTask == 널 (null) &&
  11. ! workQueue.isEmpty ()))
  12. false를 반환;
  13.  
  14. {(;;) 미국
  15. INT WC = workerCountOf (c);
  16. (화장실> = 용량 경우 ||
  17. WC> = (? corePoolSize를 코어 : maximumPoolSize를))
  18. false를 반환;
  19. 경우 (compareAndIncrementWorkerCount (c))
  20. 재 시도를 중단;
  21. C = ctl.get (); // 다시 읽어 CTL
  22. 경우 (runStateOf (C)! = RS)
  23. 재시도 계속;
  24. // 다른 CAS 인해 workerCount 변화에 실패; 내부 루프 재시
  25. }
  26. }
  27.  
  28. 부울 workerStarted = 거짓;
  29. 부울 workerAdded = 거짓;
  30. 작업자 w = NULL;
  31. {시도
  32. w = 새 작업자 (firstTask);
  33. 마지막 스레드 t = w.thread;
  34. 경우 (t! = NULL) {
  35. 최종 ReentrantLock와 mainLock = this.mainLock;
  36. mainLock.lock ();
  37. {시도
  38. // 다시 확인 잠금을 보유하고있다.
  39. ThreadFactory를 실패하거나 경우 // 돌아 가기 밖으로
  40. // 잠금을 획득하기 전에 종료합니다.
  41. RS = INT runStateOf (ctl.get ());
  42.  
  43. (RS <SHUTDOWN 경우 ||
  44. (RS == SHUTDOWN && firstTask == NULL)) {
  45. (t.isAlive ()) // PreCheck를 그 t IS 시작 가능한 경우
  46. () 새로운 예외 : IllegalThreadStateException을 던져;
  47. workers.add (w)는;
  48. S = INT workers.size ();
  49. 경우 (S> largestPoolSize)
  50. largestPoolSize의 = S;
  51. = 사실 workerAdded;
  52. }
  53. } 드디어 {
  54. mainLock.unlock ();
  55. }
  56. 경우 {(workerAdded)
  57. t.start ();
  58. workerStarted 사실 =;
  59. }
  60. }
  61. } 드디어 {
  62. 만약 (! workerStarted)
  63. (W)는 addWorkerFailed;
  64. }
  65. workerStarted를 반환;
  66. }

(1) 의사 결정 논리는 우리 첫번째보기, 더 복잡

  1. 경우 (RS> = SHUTDOWN &&
  2. ! (RS == SHUTDOWN &&
  3. firstTask == 널 (null) &&
  4. ! workQueue.isEmpty ()))
  5. false를 반환;

현재 상태가 SHUTDOWN보다 큰 경우, 판정 조건이 분명히 진짜야 직접 returnfalse 경우. 판단 조건이 거짓 인 경우 SHUTDOWN 이하의 현재 상태가, 다음, 아래로 이동하면 경우 (스레드 풀 RUNNING 상태가 잘 이해) (잘 이해, 스레드 풀은 새 작업자 A를 추가하지 확실히 닫혀) 동일의 현재 상태 SHUTDOWN : firstTask 큐 작업이 널 (null)에 해당하고 작업이있는 경우, 그것은 아래로 계속 실행 조건이 거짓 인 경우, 코드가 반환하지 않습니다 판단, null로 동일되지 않았거나 firstTask 작업 큐가 비어있는 경우,이 조건이 참 것으로 판단, false를 돌려줍니다 합니다 (처음 널 (null)와 같은 경우는 예 하오는, 따라서. 우리는 스레드 풀은 더 이상 새 작업을 수락 종료 상태를 알 수 없지만, 작업은 작업 대기열 또는 작업을 완료 할 수있다, 이것을 이해하고 작업 큐는 작업을 가지고 있지만, 또한 계속 규정. 반대의 경우, (2) 작업자 스레드의 현재 수를 결정하기 위해) 내려 가지 않을 것이다

  1. {(;;) 미국
  2. INT WC = workerCountOf (c);
  3. (화장실> = 용량 경우 ||
  4. WC> = (? corePoolSize를 코어 : maximumPoolSize를))
  5. false를 반환;
  6. 경우 (compareAndIncrementWorkerCount (c))
  7. 재 시도를 중단;
  8. C = ctl.get (); // 다시 읽어 CTL
  9. 경우 (runStateOf (C)! = RS)
  10. 재시도 계속;
  11. // 다른 CAS 인해 workerCount 변화에 실패; 내부 루프 재시
  12. }

작업자 스레드의 현재 수는 제한 매개 변수는 스레드 풀 설정, 작업자를 추가하는 CAS의 사용을 초과하지 않으며, 루프 외부에서 아래로 계속 실행합니다. 그렇지 않으면 false를 반환, 근로자가 실패 추가합니다. (3) 상기 단계 (12)의 종료 후 수행 새로운 작업자 (firstTask)는 t가 w.thread 스레드 풀을 나사산 유효한 경우, 현재 작업 스레드 풀 작업자 HashSet의 실행한다 t에 첨가하고, 다시 한번 상태를 체크 .start. 작업을 수행하기 위해 하위 스레드를 열기 전에이 시간.

하위 스레드 실행 방법

통화 t.start 위의 3 단계, 실행 방법은 노동자에 실행하는 하위 스레드를 엽니 다.

  1. 공공 무효 실행 () {
  2. runWorker (이);
  3. }
  4.  
  5. 최종 공극 runWorker (w 작업자) {
  6. () 스레드는 Thread.currentThread 중량 =;
  7. 실행 가능한 작업은 w.firstTask를 =;
  8. w.firstTask = NULL;
  9. () w.unlock; // 수 있도록 인터럽트
  10. 부울 completedAbruptly 사실 =;
  11. {시도
  12. 동안 (작업! = null의 || (작업 =를 getTask ())! = NULL) {
  13. () w.lock;
  14. // 풀 스레드를 확인 중지되면은 중단;
  15. //하지 않을 경우, 확인 스레드가 중단되지 않습니다.
  16. // 거래에 대한 두 번째 경우의 재 점검과 함께이 필요
  17. // shutdownNow의 레이스 동안 청소 인터럽트
  18. 경우 ((runStateAtLeast (ctl.get (), STOP) ||
  19. (Thread.interrupted () &&
  20. runStateAtLeast (ctl.get (), STOP))) &&
  21. ! wt.isInterrupted ())
  22. wt.interrupt ();
  23. {시도
  24. beforeExecute (중량, 작업);
  25. Throwable를 던져 = NULL;
  26. {시도
  27. task.run ();
  28. }드디어 {
  29. afterExecute (작업, 던져);
  30. }
  31. } 드디어 {
  32. 작업 = NULL;
  33. w.completedTasks ++;
  34. () w.unlock;
  35. }
  36. }
  37. completedAbruptly = FALSE;
  38. } 드디어 {
  39. processWorkerExit (completedAbruptly, w);
  40. }
  41. }

지속적를 getTask () 메소드,이 Workqueue에서 인수 작업을 통해 노동자보다도, 어떤 작업을 취득하지 않은 경우, processWorkerExit 메서드가 호출됩니다.

를 getTask ()

  1. 개인의 Runnable를 getTask () {
  2. 부울 TIMEDOUT = 거짓; // 마지막 여론 조사 () 시간 제한을 했습니까?
  3. {(;;) 미국
  4. C = INT ctl.get ();
  5. RS = INT runStateOf (c);
  6. // 필요한 경우 큐는 비어 있는지 확인하십시오.
  7. 경우 (RS> = SHUTDOWN && (RS> = STOP || workQueue.isEmpty ())) {
  8. decrementWorkerCount ();
  9. NULL을 반환;
  10. }
  11. INT WC = workerCountOf (c);
  12. // 컬링 근로자 대상이 있습니까?
  13. 부울 타이밍 된 allowCoreThreadTimeOut = || WC> corePoolSize를;
  14. 경우 ((WC> maximumPoolSize를 || (타이밍 된 && TIMEDOUT))
  15. && (WC> 1 || workQueue.isEmpty ())) {
  16. 경우 (compareAndDecrementWorkerCount (c))
  17. NULL을 반환;
  18. 계속하다;
  19. }
  20. {시도
  21. 실행 가능한 R = 타임?
  22. workQueue.poll (이 KeepAliveTime, TimeUnit.NANOSECONDS) :
  23. workQueue.take ();
  24. 경우 (R! = null이)
  25. R를 반환;
  26. TIMEDOUT 사실 =;
  27. } 캐치 (예외 : InterruptedException 재시도) {
  28. TIMEDOUT = 거짓;
  29. }
  30. }
  31. }

를 getTask 무한 루프 방법하는 방법으로서, 먼저 스레드 풀의 현재 상태를 결정

  1. 경우 (RS> = SHUTDOWN && (RS> = STOP || workQueue.isEmpty ())) {
  2. decrementWorkerCount ();
  3. NULL을 반환;
  4. }

이 판단은 물론 RS == 종료,이 Workqueue이 비어있는 경우, 분명히 직접 널 (null)을 반환해야하고, 작업에 앞서 하나의 작업자에 의해 감소, 이해된다. (를 getTask 복귀 널은 runWorker 방법은 HashSet의 작업자로부터 processWorkerExit 삭제 전류를 호출한다), 그렇지 않으면 스레드 풀에서 설명한 상기 SHUTDOWN보다 RS> 크다 (이 방법은 작업 큐에 대기하는 태스크가 실행되지는 shutdownNow의 스레드 풀에 대응하는) 경우 실행, 아래로 계속 실행됩니다. 그런 다음 스레드 스레드 풀은 현재 설정하고, 시간이 지남에 따라 허용 여부 및 상태 표시 줄 coreThread이 Workqueue 결정의 최대 수를 함께 스레드의 CAS 번호 저장는 null에 의해 작동 여부. 마지막으로, 우리는 작업 큐 세 헤드 작업에서 다음 작업에 관심을 얻기 위해 싶습니다.

  1. 실행 가능한 R = 타임?
  2. workQueue.poll (이 KeepAliveTime, TimeUnit.NANOSECONDS) :
  3. workQueue.take ();

진짜야에 시간이 초과하면 대기 시간이 아직 덜, 현재 노동자도 회수 할 수있다 workerCount corePoolSize를보다가 발생할 수도이 때,이 Workqueue R = 널에서 작업을 달성하지 않은 것보다 더 (allowCoreThreadTimeOut true로 설정)합니다. 시간 제한 거짓이 방법을 차단 호출이 Workqueue에서 작업을 얻을 경우, 인 newFixedThreadPool 항상이 Workqueue가 비어있는 경우에도 폐쇄 스레드 풀을 표시하지 않고 달성 할 수 있도록 같이 차단 메소드를 호출뿐만 아니라 작업자 스레드의 고정 된 수를 유지하기 위해 .

shutDown (shutDownNow) 방법

  1. 공개 목록 <Runnable를> shutdownNow의 () {
  2. 목록 <Runnable를> 작업;
  3. 최종 ReentrantLock와 mainLock = this.mainLock;
  4. mainLock.lock ();
  5. {시도
  6. checkShutdownAccess ();
  7. SHUTDOWN로 // shutDwonNow STOP으로 셧다운
  8. advanceRunState (STOP) (advanceRunState (SHUTDOWN))
  9. interruptWorkers () (interruptIdleWorkers)
  10. // shutdownNow의 특수
  11. 태스크 drainQueue = ();
  12. // shutDown에 특별 스케줄 할 콜백
  13. () onShutdown;
  14. } 드디어 {
  15. mainLock.unlock ();
  16. }
  17. tryTerminate ();
  18. 작업을 반환;
  19. }

셧다운 shutDownnNow 차분 법 (코드 레벨)

  • shutdownNow의 : advanceRunState (STOP), interruptWorkers의 셧다운 advanceRunState (종료), interruptIdleWorkers
  • shutDown에 더 onShutdown ();로 스케줄 onShutDown 복제하는 방법.
  • shutdownNow의 방법은 큐되지 않은 작업을 작동합니다.
  • interruptIdleWorkers

interruptIdleWorkers 与 interruptWorkers

(1) shutdownNow의

  1. 개인 무효 interruptWorkers () {
  2. 최종 ReentrantLock와 mainLock = this.mainLock;
  3. mainLock.lock ();
  4. {시도
  5. 대한 (노동자 w : 노동자)
  6. () w.interruptIfStarted;
  7. } 드디어 {
  8. mainLock.unlock ();
  9. }
  10. }

분명히, 이것은 중단 모든 스레드 (2) 종료입니다

  1. 개인 무효 interruptIdleWorkers (부울 onlyOne) {
  2. 최종 ReentrantLock와 mainLock = this.mainLock;
  3. mainLock.lock ();
  4. {시도
  5. 대한 (노동자 w : 노동자) {
  6. t = w.thread 스레드;
  7. 만약 (! t.isInterrupted () && w.tryLock ()) {
  8. {시도
  9. t.interrupt ();
  10. } 캐치 (SecurityException가 무시) {
  11. } 드디어 {
  12. () w.unlock;
  13. }
  14. }
  15. 경우 (onlyOne)
  16. 단절;
  17. }
  18. } 드디어 {
  19. mainLock.unlock ();
  20. }
  21. }

참고 onlyOne 매개 변수,이 때문에 종료 방법을 위해, 단지 내부 호출 (TRUE) tryTerminate () 메서드 호출의 interruptIdleWorkers, 다른 경우는 interruptIdleWorkers (false)를하다에,뿐만 아니라 모든되지 않았습니다 중단 된 스레드를 중단하려고합니다. 이 방법은 그 다음에 (2)에서 전술 한 3) tryTerminate tryTerminate 방법 모양

  1. 최종 공극 tryTerminate () {
  2. {(;;) 미국
  3. C = INT ctl.get ();
  4. 경우 (isRunning는 (C) ||
  5. runStateAtLeast (C, 정리) ||
  6. (runStateOf (c) == SHUTDOWN &&! workQueue.isEmpty ()))
  7. 반환;
  8. 경우을 (workerCountOf (C)! = 0) {대상 종료합니다 //
  9. interruptIdleWorkers (ONLY_ONE);
  10. 반환;
  11. }
  12.  
  13. 최종 ReentrantLock와 mainLock = this.mainLock;
  14. mainLock.lock ();
  15. {시도
  16. 경우 (ctl.compareAndSet (c, ctlOf (정리, 0))) {
  17. {시도
  18. () 종료;
  19. } 드디어 {
  20. ctl.set (ctlOf (TERMINATED, 0));
  21. termination.signalAll ();
  22. }
  23. 반환;
  24. }
  25. } 드디어 {
  26. mainLock.unlock ();
  27. }
  28. 실패 CAS에 // 다른 재시도
  29. }
  30. }

위의 코드에서 볼 수 있듯이 작업자 스레드 수는 스레드 풀의 상태가 SHUTDOWN 경우, 비어있는,이 Workqueue 스레드 풀은 0 또는 정지 상태, 작업자 스레드 0의 수, 스레드 풀은 결국 TERMINATED 상태로 있고, 모든 깨어 것 termination.awaitNanos (나노)의 호출 awaitTermination () 메소드 블록 스레드를 깨워하지 않은 때문이다.

  1. 공공 부울 awaitTermination (긴 시간 초과 예외 : InterruptedException 단위)
  2. 던져 예외 : InterruptedException {
  3. 긴 나노 = unit.toNanos (초과);
  4. 최종 ReentrantLock와 mainLock = this.mainLock;
  5. mainLock.lock ();
  6. {시도
  7. {(;;) 미국
  8. 경우 (runStateAtLeast (ctl.get (), TERMINATED))
  9. true를 반환;
  10. 만약 (나노 <= 0)
  11. false를 반환;
  12. 나노 = termination.awaitNanos (나노);
  13. }
  14. } 드디어 {
  15. mainLock.unlock ();
  16. }
  17. }

방법은 위의 TryTerminate, addWorkerFailed (), processWorkerExit () 셧다운 (), shutdownNow의 (), 제거 (Runnable를 작업) 방법으로 호출됩니다.

스레드 풀을 설명하기 5 주

스레드 풀의 위에서 언급 한 자주 실행 상태, 여기에 대한 간략한 설명.

  1. 개인 정적 최종 INT 실행 = -1 << COUNT_BITS;
  2. 개인 정적 최종 INT의 SHUTDOWN = 0 << COUNT_BITS;
  3. 개인 정적 최종 INT의 STOP = 1 << COUNT_BITS;
  4. 개인 정적 최종 INT의 정리 = 2 << COUNT_BITS;
  5. 개인 정적 최종 INT는 = 3 << COUNT_BITS 말단;

국가의 정의

  • RUNNING : 새로운 작업이 Workqueue에서 처리 작업.
  • SHUTDOWN : 새 작업을 허용하지 않습니다,하지만 작업을 완료하는 데 계속이 Workqueue
  • STOP은 : Workqueue는 미완성 작업을 처리하지 않는 새 작업을 허용하지 않습니다, 실행중인 모든 작업을 중단하려고
  • 정리 : 모든 작업이 완료되었습니다 작업자 스레드의 수는 0, 스레드 풀의 상태는 정리 () 메소드를 종료 호출 될 것입니다.
  • TERMINATED : 종료 () 메소드가 완료되었습니다

다섯 개 상태 변환

  • RUNNING -> SHUTDOWN 다음 마무리 아마도 암시 통화 종료 () 메소드 () 메서드
  • (RUNNING 또는 종료) -> STOP : 전화 shutdownNow의 () 메소드
  • SHUTDOWN -> 정리 : Workqueue는 수영장 비어 있습니다
  • STOP -> 정리가 : 풀 비어
  • 정리 -> 종료되었습니다 : 方法) (종료 完成

출처 : http://yeming.me/2016/05/07/threadPool1/

게시 된 277 개 원래 기사 · 원의 찬양 (65) · 전망 380 000 +

추천

출처blog.csdn.net/ailiandeziwei/article/details/104749570