java 원본 - ThreadPoolExecutor(3)

7463 단어
개편
  부서에서 예전에 매우 뛰는 프로그래머가 신기한 코드를 썼는데 ThreadPoolExecutor를 끊임없이 만들고 shutdown을 호출하지 않아서 라인이 너무 많이 넘친다. 그리고 생각해 보면 나는 아직 뛰지 않는 프로그래머이기 때문에 연구와 연구가 비교적 적합하다.이 글은 바로 연못의 퇴출 과정을 설명하는 것이다.자바 원본 - ThreadPoolExecutor(1) 자바 원본 - ThreadPoolExecutor(2) 자바 원본 - ThreadPoolExecutor(3)
shutdown 원본 코드 분석
  • 1. 잠금,mainLock은 스레드 탱크의 메인 잠금이고 다시 들어갈 수 있는 잠금이다.workers set이라는 스레드를 유지하는HashSet을 조작할 때mainLock을 먼저 가져와야 하고,largestPoolSize,completedTaskCount와 같은 통계 데이터를 처리할 때mainLock
  • 을 먼저 가져와야 한다.
  • 2. 호출자가 shutdown 스레드 탱크에 권한이 있는지 판단
  • 3. CAS 조작을 사용하여 스레드 탱크 상태를 shutdown으로 설정하면 shutdown 이후 새로운 작업을 받지 않습니다
  • 4, 모든 빈 스레드 인터럽트interruptIdleWorkers()
  • 5,onShutdown(),ScheduledThreadPoolExecutor에서 이 방법을 실현하였으며,shutdown()에서 처리할 수 있음
  • 6, 잠금 해제
  • 7, 스레드 풀 종료 시도tryTerminate()
  •     public void shutdown() {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //     
                checkShutdownAccess();
                
                //           SHUTDOWN,     SHUTDOWN     
                advanceRunState(SHUTDOWN);
                
                //       ,             
                interruptIdleWorkers();
    
                // ThreadPoolExecutor     
                onShutdown(); // hook for ScheduledThreadPoolExecutor
            } finally {
                mainLock.unlock();
            }
            //       TERMINATED
            tryTerminate();
        }
    
    
        private void advanceRunState(int targetState) {
            for (;;) {
                int c = ctl.get();
                //        SHUTDOWN
                if (runStateAtLeast(c, targetState) ||
                    ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
                    break;
            }
        }
    
        
        // onlyOne      false
        private void interruptIdleWorkers(boolean onlyOne) {
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //     worker,            worker    
                for (Worker w : workers) {
                    Thread t = w.thread;
                    if (!t.isInterrupted() && w.tryLock()) {
                        try {
                            //            ,              
                            //                           
                            //               
                            t.interrupt();
                        } catch (SecurityException ignore) {
                        } finally {
                            w.unlock();
                        }
                    }
                    if (onlyOne)
                        break;
                }
            } finally {
                mainLock.unlock();
            }
        }
    

    shutdownNow 소스 분석
      shutdown Now () 와 shutdown () 의 대체적인 절차는 비슷하다. 차이점은 다음과 같다.
  • 1. 스레드 탱크를 stop 상태로 업데이트
  • 2, interruptWorkers()를 호출하여 실행 중인 라인을 포함하여 모든 라인을 중단합니다
  • 3、workQueue에서 처리할 작업을 하나의List로 옮기고 방법이 마지막에 되돌아와서 shutdownNow() 이후에workQueue의 작업을 처리하지 않는다는 것을 설명한다
  •     public List shutdownNow() {
            List tasks;
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //     
                checkShutdownAccess();
                
                //         stop
                advanceRunState(STOP);
    
                //       
                interruptWorkers();
    
                //           
                tasks = drainQueue();
            } finally {
                mainLock.unlock();
            }
    
            //       TERMINATED
            tryTerminate();
    
            return tasks;
        }
    

    awaitTermination 소스 분석
      스레드 탱크 상태가 TERMINATED로 바뀌면 되돌아오거나 시간이 초과됩니다.전체 과정이 자물쇠를 독점하기 때문에 일반적으로 shutdown이나 shutdown Now를 호출해서 사용합니다.
  • 대기 중 시간 초과가 발견되지 않으면 for 순환을 통해 시간 초과를 계속 기다립니다
  •     public boolean awaitTermination(long timeout, TimeUnit unit)
            throws InterruptedException {
            long nanos = unit.toNanos(timeout);
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                for (;;) {
                    if (runStateAtLeast(ctl.get(), TERMINATED))
                        return true;
                    if (nanos <= 0)
                        return false;
                    nanos = termination.awaitNanos(nanos);
                }
            } finally {
                mainLock.unlock();
            }
        }
    

    작업 스레드 워커 로직 종료
    \task를null로 가져오면while 순환을 종료하고finally 부분의 논리를 실행합니다. 즉,processWorkerExit () 방법으로 작업을 수행합니다.
        final void runWorker(Worker w) {
            Thread wt = Thread.currentThread();
            Runnable task = w.firstTask;
            w.firstTask = null;
            w.unlock(); // allow interrupts
            boolean completedAbruptly = true;
            try {
                //        null,            
                while (task != null || (task = getTask()) != null) {
                    w.lock();
                    if ((runStateAtLeast(ctl.get(), STOP) ||
                         (Thread.interrupted() &&
                          runStateAtLeast(ctl.get(), STOP))) &&
                        !wt.isInterrupted())
                        wt.interrupt();
                    try {
                        beforeExecute(wt, task);
                        Throwable thrown = null;
                        try {
                            task.run();
                        } catch (RuntimeException x) {
                            thrown = x; throw x;
                        } catch (Error x) {
                            thrown = x; throw x;
                        } catch (Throwable x) {
                            thrown = x; throw new Error(x);
                        } finally {
                            afterExecute(task, thrown);
                        }
                    } finally {
                        task = null;
                        w.completedTasks++;
                        w.unlock();
                    }
                }
                completedAbruptly = false;
            } finally {
                //       
                processWorkerExit(w, completedAbruptly);
            }
        }
    

      getTask () 방법 (rs>= SHUTDOWN & (rs>= STOP | workQueue.isEmpty ()) 에서 우리는 SHUTDOWN으로 상태를 설정하고 workQueue가 비어 있으면 null로 되돌아와 외부 순환 중 라인의 작업을 종료하고 라인의 종료를 실현합니다.
        private Runnable getTask() {
            boolean timedOut = false; // Did the last poll() time out?
    
            for (;;) {
                int c = ctl.get();
                int rs = runStateOf(c);
    
                // Check if queue empty only if necessary.
                if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                    decrementWorkerCount();
                    return null;
                }
    
                int wc = workerCountOf(c);
    
                // Are workers subject to culling?
                boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
    
                if ((wc > maximumPoolSize || (timed && timedOut))
                    && (wc > 1 || workQueue.isEmpty())) {
                    if (compareAndDecrementWorkerCount(c))
                        return null;
                    continue;
                }
    
                try {
                    Runnable r = timed ?
                        workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                        workQueue.take();
                    if (r != null)
                        return r;
                    timedOut = true;
                } catch (InterruptedException retry) {
                    timedOut = false;
                }
            }
        }
    

    참고 문장
    자바 중선 스레드 탱크ThreadPoolExecutor 원리 탐구 자바 스레드 탱크ThreadPoolExecutor 사용 및 분석(3) - 정지 스레드 탱크 원리

    좋은 웹페이지 즐겨찾기