스레드 풀을 사용할 때 shutdown() 메서드를 호출한 후 스레드 풀은 더 이상 새로운 실행 작업을 허용하지 않습니다. 그러나 shutdown() 메서드를 호출하기 전에 작업 대기열에 배치된 작업은 여전히 실행되어야 합니다. 이 메서드는 비차단 메서드이며 호출된 후 즉시 반환됩니다. 반환되기 전에 작업 대기열의 모든 작업이 실행될 때까지 기다리지 않습니다. 아래와 같이 shutdown() 메소드의 소스코드를 살펴보겠습니다.
public void shutdown() { //获取线程池的全局锁 final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers(); //为ScheduledThreadPoolExecutor调用钩子函数 onShutdown(); // hook for } finally { //释放线程池的全局锁 mainLock.unlock(); } //尝试将状态变为TERMINATED tryTerminate(); }
일반적으로 shutdown() 메서드의 코드는 비교적 간단합니다. 먼저 스레드 풀을 닫을 수 있는 권한이 있는지 확인합니다. 권한이 있으면 작업 스레드를 중단할 수 있는 권한이 있는지 다시 확인합니다. 권한이 없으면 SecurityException 예외가 발생합니다. 코드는 다음과 같습니다.
//检查是否有关闭线程池的权限 checkShutdownAccess(); //将当前线程池的状态设置为SHUTDOWN advanceRunState(SHUTDOWN); //中断Worker线程 interruptIdleWorkers();
그 중 checkShutdownAccess() 메소드의 구현 코드는 다음과 같습니다.
private void checkShutdownAccess() { SecurityManager security = System.getSecurityManager(); if (security != null) { security.checkPermission(shutdownPerm); final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) security.checkAccess(w.thread); } finally { mainLock.unlock(); } } }
checkShutdownAccess() 메서드의 코드는 비교적 이해하기 쉽습니다. 스레드 풀의 전역 잠금이 사용되는 동안 스레드 풀을 닫을 수 있는 권한이 있는지 확인하는 것입니다.
다음으로 아래와 같이 advanceRunState(int) 메서드의 소스 코드를 살펴보겠습니다.
private void advanceRunState(int targetState) { for (;;) { int c = ctl.get(); if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c)))) break; } }
advanceRunState(int) 메서드의 전체 논리는 현재 스레드 풀 상태가 지정된 상태인지 확인하는 것입니다. shutdown() 메서드에 전달된 상태는 SHUTDOWN이면 직접 반환됩니다. SHUTDOWN이 아닌 경우 현재 스레드 풀 상태를 SHUTDOWN으로 설정합니다.
다음으로 아래와 같이 showdown() 메서드에서 호출되는 InterruptIdleWorkers() 메서드를 살펴보겠습니다.
private void interruptIdleWorkers() { interruptIdleWorkers(false); }
interruptIdleWorkers() 메서드가 InterruptIdleWorkers(boolean) 메서드를 호출하는 것을 볼 수 있습니다. 아래 그림과 같이 InterruptIdleWorkers(boolean) 메서드의 소스 코드를 계속 살펴보세요.
private void interruptIdleWorkers(boolean onlyOne) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { 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(); } }
위 코드의 전체 논리는 다음과 같습니다. 스레드 풀의 전역 잠금을 획득하고 모든 작업자 스레드를 순환하며 스레드가 중단되었는지 여부를 감지하고 그렇지 않은 경우 작업자 스레드가 잠금을 획득하고 스레드의 중단 메서드를 실행합니다. 스레드가 획득한 잠금입니다. 이때 onlyOne 파라미터가 true이면 루프를 종료합니다. 그렇지 않으면 모든 작업자 스레드를 반복하고 동일한 작업을 수행합니다. 마지막으로 스레드 풀의 전역 잠금이 해제됩니다.
다음으로 shutdownNow() 메서드를 살펴보겠습니다.
스레드 풀의 shutdownNow() 메서드가 호출되면 스레드 풀은 더 이상 새로운 실행 작업을 허용하지 않고 작업 큐에 존재하는 작업은 삭제되며 실행 중인 Worker 스레드는 또한 즉시 중단됩니다. 동시에 이 메서드는 현재 작업 대기열에서 삭제된 작업 목록인 반환 값을 갖습니다.
shutdownNow() 메소드의 소스코드는 다음과 같습니다.
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //检查是否有关闭权限 checkShutdownAccess(); //设置线程池的状态为STOP advanceRunState(STOP); //中断所有的Worker线程 interruptWorkers(); //将任务队列中的任务移动到tasks集合中 tasks = drainQueue(); } finally { mainLock.unlock(); } /尝试将状态变为TERMINATED tryTerminate(); //返回tasks集合 return tasks; }
shutdownNow() 메서드 소스 코드의 전체 논리는 shutdownNow() 메서드가 스레드 풀의 상태를 STOP으로 설정하고 모든 Worker 스레드를 중단하며, 작업 대기열의 모든 작업을 작업 컬렉션으로 이동하고 반환합니다.
shutdownNow() 메서드가 모든 스레드를 중단하면 InterruptWorkers() 메서드가 호출되는 것을 볼 수 있습니다. 다음으로, 아래와 같이 InterruptWorkers() 메서드의 소스 코드를 살펴보겠습니다.
private void interruptWorkers() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { for (Worker w : workers) w.interruptIfStarted(); } finally { mainLock.unlock(); } }
interruptWorkers() 메서드의 논리는 비교적 간단합니다. 즉, 스레드 풀의 전역 잠금을 획득하고, 모든 작업자 스레드를 순환하고, 스레드를 순차적으로 중단하고, 마지막으로 스레드 풀의 전역 잠금을 해제하는 것입니다.
interruptWorkers() 메서드 내부에서는 실제로 Worker 클래스의 InterruptIfStarted() 메서드가 호출되어 스레드를 중단합니다. 아래 그림과 같이 Worker 클래스의 InterruptIfStarted() 메서드 소스 코드를 살펴보겠습니다.
void interruptIfStarted() { Thread t; if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) { try { t.interrupt(); } catch (SecurityException ignore) { } } }
스레드를 중단하기 위해 Thread 클래스의 Interrupt() 메서드를 본질적으로 호출한다는 사실을 발견했습니다.
스레드 풀이 waitTermination(long, TimeUnit) 메서드를 호출하면 호출자의 스레드를 차단하고 스레드 풀의 상태가 TERMINATED로 변경되거나 타임아웃될 때까지 반환하지 않습니다. 기간에 도달했습니다. 다음으로 아래와 같이 waitTermination(long, TimeUnit) 메소드의 소스코드를 살펴보겠습니다.
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { //获取距离超时时间剩余的时长 long nanos = unit.toNanos(timeout); //获取Worker线程的的全局锁 final ReentrantLock mainLock = this.mainLock; //加锁 mainLock.lock(); try { for (;;) { //当前线程池状态为TERMINATED状态,会返回true if (runStateAtLeast(ctl.get(), TERMINATED)) return true; //达到超时时间,已超时,则返回false if (nanos <= 0) return false; //重置距离超时时间的剩余时长 nanos = termination.awaitNanos(nanos); } } finally { //释放锁 mainLock.unlock(); } }
위 코드의 전체 논리는 다음과 같습니다. 먼저 작업자 스레드의 배타적 잠금을 얻은 다음 루프를 통해 현재 스레드 풀이 이미 TERMINATED 상태인지 확인하고, 그렇지 않으면 true를 직접 반환합니다. 시간이 초과된 경우 false를 반환합니다. 타임아웃이 되지 않으면 타임아웃 전 남은 시간을 재설정하세요. 다음으로 다음 사이클에 진입하여 현재 Thread Pool이 TERMINATED 상태인지 다시 확인하고, 그렇다면 바로 true를 반환하고, 그렇지 않으면 타임아웃이 되었는지 확인하여 false를 반환한다. 타임아웃이 되지 않으면 타임아웃 전 남은 시간을 재설정하세요. 이 루프는 스레드 풀 상태가 TERMINATED가 되거나 시간 초과될 때까지 계속됩니다.
위 내용은 Java 스레드 풀을 정상적으로 종료하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!