본문 바로가기
안드로이드/Thread

ThreadPoolExecutor 사용하기.

by 파워킴 2014. 1. 17.
반응형

ThreadPoolExecutor 

* 항상 ThreadPool에 대해 관심은 있었으나 

뭔가 복잡할거 같고 어렵고 접근하기 힘들어 그냥 Thread로만 대충 사용하다 보니 Multi Thread 환경에서 대략 난감인 경우들이 좀 있다.

그래서 찾아 보니 .ThreadPoolExecutor 라는 놈을 발견하게 되었다.

 

이것의 사용법을 함 알아보자.

ThreadPoolExecutor(int corePoolSize, 
                    int maximumPoolSize, 
                    long keepAliveTime, 
                    TimeUnit unit, 
                    BlockingQueue <Runnable > workQueue){
}

  • corePoolSize : 실행할 최소 Thread수.
  • maximumPoolSize : 최대 Thread 지원수
  • keepAliveTime : 현재 풀에 corePoolSize 의 수보다 많은 thread가 있는 경우, 초과한 만큼의 thread는, IDLE 상태가 되어 있는 기간이 keepAliveTime 를 넘으면(자) 종료합니다
  •  unit : 시간단위.
  •  workQueue : 처리 큐

( Java Doc 참고 : http://xrath.com/javase/ko/6/docs/ko/api/java/util/concurrent/ThreadPoolExecutor.html )

 

 

여기서 중요한것은 큐입니다.

JavaDoc을 보면.BlockingQueue 에 적용가능한 Queue는 다음과 같습니다.

 

SynchronousQueue 

  • 워크 큐에 적절한 디폴트의 선택사항은, 태스크를 보관 유지하지 않고 thread에 핸드 오프.
  • 일반적으로 직접 핸드 오프에서는, 송신된 새로운 태스크가 거부되는 것을 회피하기 위해서, 안 바운드 형식의 maximumPoolSizes 가 필요합니다.
  • 이것에 의해, 평균해 처리 능력을 넘는 속도로 커멘드가 차례차례로 도착하면(자), 안 바운드 형식의 thread가 커질 가능성이 있습니다.

 

ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new SynchronousQueue  <Runnable>()  );
for( int i = 0; i < 6; i++ ) { 
    threadPool.execute( new Runnable()  { 
        public void run() { 
            System.out.println( "Thread " + Thread.currentThread().getName() + " Start" ); 
            try { 
            	Thread.sleep( 1000 ); 
            } catch( Exception e ) {
            
            }  
            System.out.println( "Thread " + Thread.currentThread().getName() + " End" ); 
        } 
    } ); 
}

- 2개의 Thread사용 
- 최대 4개 Thread사용  ( SynchronousQueue 사용시에는 maximumPoolSizes(최대 Thread개수) 값이 필요
- 60초의 Timeout 설정 
- 큐는 SynchronousQueue   

 

- 이렇게 하면 최대 Thread개수인 4개를 모두 사용하게 됨.

- for문을 통해 Thread 실행시 6개의 Thread가 실행되는데 최대 사용가능한 Thread 개수는 4개 이므로 실행중 

RejectedExecutionException() 발생함.

SynchronousQueue 의 경우는 Task를 보관하지 않고 바로 실행하므로 최대 개수 4를 넘는 Thread 실행시 Exeption 발생함. )

 

 

LinkedBlockingQueue

  • corePoolSize 의 모든 thread가 Busy 상태인 경우에, 새로운 태스크는 큐내에서 대기합니다. 이것에 의해, corePoolSize 를 넘는 thread는 작성되지 않게 됩니다. 
    즉 maximumPoolSize 의 값은 효과가 없어집니다. (maximumPoolSize 값은 의미 없음)
  • 각 태스크가 완전하게 독립하고 있기 (위해)때문에, 태스크가 상호의 실행에 영향을 주지 않는 경우는 이 방식이 적절하다라고 하는 것이 있습니다 (Web 페이지 서버의 경우 등).
  • 이 방식의 큐잉은, 일시적으로 급증한 요구를 처리하는 경우 등은 편리합니다만, 평균 해 처리 능력을 넘는 속도로 커멘드가 차례차례로 도착하면, 안 바운드 형식의 워크 큐가 커질 가능성이 있습니다.  
ThreadPoolExecutor threadPool = new ThreadPoolExecutor( 2, 4, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>()  );

for( int i = 0; i < 6; i++ ) {
	threadPool.execute( new Runnable() {
		public void run()
		{
			System.out.println( "Thread " + Thread.currentThread().getName() + " Start" );
			
			try { 
				Thread.sleep( 1000 );
			} catch ( Exception e ) {

			} 
			
			System.out.println( "Thread " + Thread.currentThread().getName() + " End" );
		}
	} );
}

- 2개의 Thread사용

- 최대 4개 Thread사용 (LinkedBlockingQueue에서는  maximumPoolSize 값은 의미 없음 )

- 60초의 Timeout 설정

- 큐는 LinkedBlockingQueue 

 

[ 실행 결과 ]

Thread pool-1-thread-1 Start  
Thread pool-1-thread-2 Start
Thread pool-1-thread-1 End
Thread pool-1-thread-1 Start
Thread pool-1-thread-2 End
Thread pool-1-thread-2 Start
Thread pool-1-thread-1 End
Thread pool-1-thread-1 Start
Thread pool-1-thread-2 End
Thread pool-1-thread-2 Start
Thread pool-1-thread-1 End
Thread pool-1-thread-2 End

* 이렇게 하면 총 6개의 Thread가 돌지만. 2개의 Thread가 실행되고 나머지는 큐에 대기하고 있다가 2개의 Thread가 종료되면 이후 실행된다. 

 

 

ArrayBlockingQueue

  • 한정된 maximumPoolSizes 로 사용하면 자원 부족을 회피할 수 있습니다만, 조정과 제어가 어려워질 가능성이 있습니다. 큐 사이즈와 최대 풀 사이즈는 서로 트레이드 오프의 관계가 되는 일이 있습니다. 

 

반응형

'안드로이드 > Thread' 카테고리의 다른 글

ExecutorService  (0) 2015.12.08

댓글