본문 바로가기

책정리/EfectiveJava

스레드보다는 실행자, 태스크, 스트림을 애용하라

초판에서는 작업큐를 설명 했지만 java.util.concurrent 패키지가 등장하므로 다음 한줄로 작업큐를 대체할 수 있게 됨

ExecutorService exec = Executors.newSingleThreadExecutor();
//실행 태스크를 넘기는 방법
exec.execute(runnable);
//실행자를 종료시키는 방법
exec.shutdown

실행자 서비스의 주요 기능

  • 특정 태스크가 완료되기를 기다림 (get메서드)
  • 아무것 하나 (invokeAny) 혹은 모든 태스크 (invokeAll)가 완료되기를 기다림
  • 종료하기를 기다림(awaitTermination)
  • 완료된 태스크들의 결과를 차례로 받음 (ExecutorCompletionService)
  • 태스크를 특정 시간에 혹은 주기적으로 실행하게 함(ScheduledThreadPoolExecutor)

Executors.newCachedTrehadPool 

  • 처리할 스레드가 많아지면 많아지는 만큼 스레드를 증가
  • 쉬는 스레드가 많다면 스레드를 종료
  • 스레드 제한이 없기 때문에 조심해서 사용해야 함.
  • 작은 프로그램이나 가벼운 서버에 적합
  • 무거운 프로덕션 서버에는 좋지 못하다

Executors.newFixedThreadPool

  • 주어진 스레드만큼 생성하고 그 수를 유지함
  • 생성된 스레드중 일부 작업이 종료되었다면 스레드를 다시 생성하여 주어진 스레드 수를 맞춤
  • 무거운 프로덕션 서버에 적합

작업 큐를 손수 만드는 일을 삼가하고 스레드를 직접 다루는 것도 일반적으로 삼가 해야함.

스레드를 직접 다루면 스레드가 작업 단위와 수행 매커니즘 역할을 모두 수행하게 됨

 

포크-조인 태스크

 - 포크-조인 풀이라는 특별한 실행자 서비스가 실행해 줌

 - 포크-조인 태스크의 인스턴스는 작은 하위 태스크로 나뉠 수 있음

  - 포크-조인 풀을 구성하는 스레드들이 이 태스크들을 처리함

  - 일을 먼저 끝낸 스레드는 다른 스레드의 남은 태스크를 가져와 대신 처리할 수 도 있다

 - CPU를 최대한 활용하면서 높은 처리량과 낮은 지연시간을 달성한다.