본문 바로가기

아는 만큼 보인다/Concurrency

Executors.newCachedThreadPool()의 TIMED_WAITING 스레드

정적 팩토리 메소드 Executors.newCachedThreadPool() 는 스레드를 재사용할 수 있는 스레드풀을 만들어준다.

이 스레드풀 안에서 수행이 완료된 스레드는 바로 소멸되지 않고 

풀 안에서 (기본값을 바꾸지 않았다면) 60초 동안 TIMED_WAITING 상태로 재사용되기를 기다린다. 

재사용되지 않고 60초가 지나면 풀에서 제거된다.


직접 확인해보자.

public class Hello {

public static void main(String[] args) throws IOException, InterruptedException {

Executor pool = Executors.newCachedThreadPool();

// 풀 안에 스레드 생성 및 실행

pool.execute(new Runnable() {

@Override

public void run() {

System.out.println("hello cached thread pool!");

// 특별히 하는 일 없이 바로 종료

}

});

// 덤프파일 확인할 수 있도록, 2분 동안 프로세스 살려두자.

for(int i=1; i <= 120; i ++) {

Thread.sleep(1000);

System.out.println(i + " seconds: " + pool.toString());

// 스레드덤프파일 생성 명령

// $ jstack {pid} > dumps.log

// 60초 전과 후의 덤프파일 내용을 비교해보자.

}

}

}


위 코드를 실행시키고, 프로세스가 살아있는 동안 스레드 덤프파일을 생성해보자.

$ jstack {pid} > dumps.log


60초 경과 전과 후에 생성된 덤프파일을 비교해보자.


60초 경과전 덤프파일 

... 생략 ...

"pool-1-thread-1" #13 prio=5 os_prio=0 tid=0x0000000016ebc800 nid=0x3e20 waiting on condition [0x0000000017acf000]

   java.lang.Thread.State: TIMED_WAITING (parking)

at sun.misc.Unsafe.park(Native Method)

- parking to wait for  <0x00000000eb30e498> (a java.util.concurrent.SynchronousQueue$TransferStack)

at java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)

at java.util.concurrent.SynchronousQueue$TransferStack.awaitFulfill(Unknown Source)

at java.util.concurrent.SynchronousQueue$TransferStack.transfer(Unknown Source)

at java.util.concurrent.SynchronousQueue.poll(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.lang.Thread.run(Unknown Source)

... 생략 ...


60초 경과후 덤프파일

"덤프파일에서 해당 스레드가 사라졌다"


console에 찍힌 로그에서도 pool의 스레드 통계를 확인 할 수 있다. 60초가 경과 하면 pool size가 줄었다.

... 생략 ...

58 seconds: java.util.concurrent.ThreadPoolExecutor@70dea4e[Running, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 1]

59 seconds: java.util.concurrent.ThreadPoolExecutor@70dea4e[Running, pool size = 1, active threads = 0, queued tasks = 0, completed tasks = 1]

60 seconds: java.util.concurrent.ThreadPoolExecutor@70dea4e[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]

61 seconds: java.util.concurrent.ThreadPoolExecutor@70dea4e[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]

... 생략 ...