728x90
반응형
* Executor
 * Executor는 굉장히 단순한 인터페이스로 보이지만 아주 다양한 여러 가지 종류의 작업 실행 정책을 지원하는 
 * 유연하면서도 강력한 비동기적 작업 실행 프레임웍의 근간을 이루는 인터페이스다
 
 * Executor는 작업등록(task submission) ,작업실행(task Execution)을 분리하는 표준적인 방법이며,
 * 각 작업은 Runnable의 형태로 정의한다.
 
 * Executor인터페이스를 구현한 클래스는 작업의 라이프 사이클을 관리하는 기능도 갖고 있고,
 * 몇가지 통계값을 뽑아내거나 애플리케이션에서 작업 실행 과정을 관리하고 모니터링하기 위한 기능도 갖고 있다.
 * 
 * Executor의 구조는 프로듀서-컨슈머 패턴에 기반하고 있으며, 작업을 생성해 등록하는 클래스가 
 * 프로듀서(처리해야할 작업을 생성하는 주체)가 되고, 작업을 실제로 실행하는 스레드가 
    컨슈머(생성된 작업을 처리하는 주체)가 되는 모양을 갖추고 있다.

 * 일반적으로 프로듀서-컨슈머 패턴을 애플리케이션에 적용해 구현할 수 있는 가장 쉬는 방법이
   바로 Executor 프레임웍을 사용하는 방법이다.
  1) Executors.newFixedThreadPool(100);  //100개의 스레드
    - 처리할 작업이 등록되면 그에 따라 실제 작업할 스레드를 하나씩 생성한다.
    - 생성할 수 있는 스레드의 최대 개수는 제한되어 있다.
    -  제한된 개수까지 스레드를 생성하고 나면 더이상 생성하지 않고 스레드 수를 유지한다.
  2) Executors.newCachedThreadPool();
    - 캐시 스레드풀은 현재 풀에 갖고 있는 스레드의 수가 처리할 작업의 수보다 많아서 쉬는 스레드가 많이 발생할 때 쉬는 스레드를
        종료시켜 훨씬 유연하게 대응 할 수 있으며, 처리할 작업의 수가 많이 지면 필요한 만큼 스레드를 새로 생성한다.
    - 스레드의 수에 제한을 두지 않는다.
   3) Executors.newSingleThreadExecutor();
  - 단일 스레드로 동작하는 Executor 로서 작업을 처리하는 스레드가 단 하나 뿐이다.
  - 만약 작업중에 Exeception 이 발생해 비정상적으로 종료되면 새로운 스레드를 하나 생성해 나머지 작업을 실행한다.
  - 등록된 작업은 설정된 큐에서 지정하는 순서(FIFO,LIFO,우선순위)에 따라 반드시 순차적으로 처리된다.
   4) Executors.newScheduledThreadPool(100);
  - 일정시간 이후에 실행하거나 주기적으로 작업을 실행할 수 있으며, 스레드의 수가 고정되어 있는 형태의
     Executor.Timer 클래스의 기능과 유사하다.

ExecutorService
  - newFixedThreadPool,newCachedThreadPool 팩토리 메소드는 일반화된 형태로 구현되어 있는  ThreadPoolExecutor
       클래스의 인스턴스를 생성한다.
  - 생성된 ThreadPoolExecutor 인스턴스에 설정값을 조절해 필요한 형태를 갖추고 사용할 수도 있다.
  - Executor 를 구현한 클래스는 대부분 작업을 처리하기 위한 스레드를 생성하도록 되어 있다. 하지만 JVM 은 모든 스레드가 
     종료되기 전에는 종료하지 않고 대기하기 때문에 Executor를 제대로 종료시키지 않으면 JVM 자체가 종료되지 않고
      대기하기도 한다.
  - Executor는 작업을 비동기적으로 실행하기 때문에 앞서 실행시켰던 작업의 상태를 특정시점에 정확히 파악하기가 어렵다.
     어떤작업은 이미 완료되었을 수도 있고, 몇몇 작업은 실행중일 수 있고, 또다른 작업은 큐에서 대기하고 있을 수 있다. 
  - 애플리케이션을 종료하는 과정을 보면 안정한 종료방법과(작업을 새로 등록하지 못하고, 시작된 모든작업이 끝날때 까지 기다림) 
      강제적인 종료 방법이 있겠다. 물론 그사이에 위치하는 여러가지 종료방법이 있겠다.
  - Executor가 애플리케이션에 스레드 풀등의 서비스를 제공한다는 관정으로 생각해 보면 Executor 역시 안전한 방법이든,
      강제적인 방법이든 종료절차를 밟아야할 필요가 있다.
  - 그리고 종료절차를 밟는 동안 실행중이거나,대기중인 작업을 어떻게 처리했는지 애플리케이션에 알려줄 의무가 있다.
  - 이처럼 서비스를 실행하는 동작주기와 관련해 Ececutor를 상속받은 ExecutorService 인터페이스에는 동작주기를 관리할 수 있
    는 여러가지 메소드가 추가되어 있다.
public interface ExecutorService extends Executor{
void shutdown();                                                --> 안전한 종료
List<Runnable> shutdownNow();                         --> 강제종료
boolean isShutdown(); 
boolean isTerminated();
boolean awaitTermination(long timeout,TimeUnit unit) throw InterruptedExeception;
                                                      --> ExecutorService가 종료상태로 들어갈 때까지 기다리고자 할때 사용
..,
}

보통 shutdown() 메소드 실행 후 바로 awaitTermination()을 실행하면 Executor를 직접 종료시키는것과
비슷한 효과를 얻을 수 있다.
ExecutorService exec= Executors.newFixedThreadPool(100);
Callable<V> task = new Callable<V>() {

public V call() throws Exception {
return null;
}
};
Future<V> a = exec.submit(task);
a.get();

 

 

 

 

 

 * ThreadPoolExecutor :

 * Executors 클래스에 들어있는 newCachedThreadPool, newFixedThreadPool ,newScheduledThreadPool

 * 과 같은 팩토리메소드에서 생성해 주는 Executor에 대한 기본적인 내용이 구현되어 있는 클래스이다.

 

 

 * 팩토리메소드를 사용해 만들어진 스레드 풀의 기본 실행 정책이 요구 사항에 잘 맞지 않는다면 ThreadPoolExecutor 클래스의

 * 생성자를 직접 호출해 스레드 풀을 생성할 수 있으며, 생성자에 넘겨주는 값을 통해 스레드 풀의 설정을 마음대로 조절할 수 있다.

 

public ThreadPoolExecutor (int corePoolSize,                  // 스레드풀을 사용할때 원하는 스레드의 개수

int maximumPoolSize,           //동시에 동작할 수 있는 스레드의 최대값

long keepAliveTime,             //스레드의 유지시간

TimeUnit unit,

BlokingQueue<Runable> workQueue,

ThreadFactory threadFactory,

RehectedExecutionHandler handker)

{....}

 

* newFixedThreadPool

*    - 스레드풀의 코어크기,최대크기를 newFixedThreadPool(100) 처럼 파라미터로 지정한 값으로 설정 

*    - 시간제한은 무제한

*    - LinkedBlokingQueue 사용

* newCachedThreadPool

*    - 스레드풀의 최대 크기를 Integer.MAX_VALUE값으로 설정

*    - 코어 크기 :0

*    - 스레드 유지시간은 1분

*    - SynchronousQueue 사용 : 프로듀소에서 생긴 작업을 컨슈머인 스레드에 직접 전달

*       따지고 보면 큐가 아니며, 단지 스레드 간에 작업을 넘겨주는 기능을 담당함

*    - SynchronousQueue에 작업을 추가하려면 컨슈머인 스레드가 이미 작업을 받기위해 대기하고 있어야 하며,

*       대기중인 스레드가 없는 상태에서 스레드의 갯수가 최대 크기보다 작다면 새로운 스레드를 생성시켜 동작한다.

*       최대크기에 다다른 상태라면 작업을 거부하도록 되어 있다.

*    따라서 newCachedThreadPool에서 만들어낸 스레드풀은 크기가 무제한 늘어나며, 

     사용량이 줄어들면 스레드갯수가 적장히 줄어든다

 

 

728x90
반응형
블로그 이미지

nineDeveloper

안녕하세요 현직 개발자 입니다 ~ 빠르게 변화하는 세상에 뒤쳐지지 않도록 우리모두 열심히 공부합시다 ~! 개발공부는 넘나 재미있는 것~!

,