2012-06-28 7 views
11

Java (java.util.concurrent)의 스레드 풀을 구현해야합니다.이 스레드 풀은 유휴 상태 일 때 최소값을 가지며 상한까지 증가하지만 작업이 완료 될 때보 다 더 빨리 작업에 제출되고 모든 작업이 완료되고 더 이상 작업이 제출되지 않을 때 하한으로 축소됩니다.동적 (확장/축소) 스레드 풀 만들기

어떻게 구현합니까? 이것은 꽤 일반적인 사용 시나리오 일 것이라고 생각하지만 분명히 java.util.concurrent.Executors 팩토리 메소드는 많은 작업이 제출 될 때 무한정 증가하는 고정 크기 풀과 풀만 생성 할 수 있습니다. ThreadPoolExecutor 클래스는 corePoolSizemaximumPoolSize 매개 변수를 제공하지만 문서에서는 corePoolSize 개 이상의 스레드를 동시에 가질 수있는 유일한 방법은 바운드 작업 큐를 사용하는 것입니다.이 경우 바운드 작업 큐를 사용하는 경우 maximumPoolSize 개의 스레드에 도달 한 경우, 너 자신을 다루어야하는 직업 거부를받을거야? 나는 이것을 생각해 냈다 :

//pool creation 
ExecutorService pool = new ThreadPoolExecutor(minSize, maxSize, 500, TimeUnit.MILLISECONDS, 
    new ArrayBlockingQueue<Runnable>(minSize)); 
... 

//submitting jobs 
for (Runnable job : ...) { 
    while (true) { 
     try { 
      pool.submit(job); 
      System.out.println("Job " + job + ": submitted"); 
      break; 
     } catch (RejectedExecutionException e) { 
      // maxSize jobs executing concurrently atm.; re-submit new job after short wait 
      System.out.println("Job " + job + ": rejected..."); 
      try { 
       Thread.sleep(300); 
      } catch (InterruptedException e1) { 
      } 
     } 
    } 
} 

나는 무엇인가 내려다 본다? 이 작업을 수행하는 더 좋은 방법이 있습니까? 또한 요구 사항에 따라 위 코드가 적어도 (total number of jobs) - maxSize 작업이 완료 될 때까지 완료되지 않을 수도 있습니다. 따라서 풀에 임의의 수의 작업을 제출하고 완료 할 때까지 기다리지 않고 즉시 진행할 수 있기를 원한다면 어떻게 관리 할 수있는 전용 "작업 정리"스레드가 없어도이를 수행 할 수있는 방법을 알 수 없습니다 제출 된 모든 작업을 보관 유지하는 필수 unbounded 큐 AFAICS, ThreadPoolExecutor 자체에 대해 무한 대기열을 사용하는 경우 해당 스레드 수가 corePoolSize 이상으로 커지지 않습니다.

+3

나는 동적 크기의 스레드 풀의 유용성을 보지 못한다는 것을 인정해야한다. 응용 프로그램의 가동 시간 동안 보드의 프로세서 수가 변경됩니까? – corsiKa

+3

'newCachedThreadPool'이 상황에 맞지 않는 이유는 무엇입니까? 더 이상 사용되지 않는 스레드는 자동으로 제거됩니다. – Tudor

+0

유휴 스레드가 죽지 않았다면 어떻게 될까요? 항상 최대 크기의 고정 크기 풀을 가지고 있다고 가정 해보십시오. 무슨 일이 일어날 지? –

답변

4

동일한 스레드를 사용하는 RejectedExecutionHandler을 할당하여 차단 대기열로 작업을 전송하는 데 도움이되는 트릭입니다. 그것은 현재 스레드를 차단하고 일종의 루프에 대한 필요성을 제거합니다.

How can I make ThreadPoolExecutor command wait if there's too much data it needs to work on?

여기 그 대답에서 복사 한 거부 핸들러의 :

여기에 내 대답을 참조하십시오.

final BlockingQueue queue = new ArrayBlockingQueue<Runnable>(200); 
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(nThreads, nThreads, 
     0L, TimeUnit.MILLISECONDS, queue); 
// by default (unfortunately) the ThreadPoolExecutor will call the rejected 
// handler when you submit the 201st job, to have it block you do: 
threadPool.setRejectedExecutionHandler(new RejectedExecutionHandler() { 
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { 
     // this will block if the queue is full 
     executor.getQueue().put(r); 
    } 
}); 

그런만큼 당신이 어떤 스레드 코어 스레드 위에서 만든되기 전에 처음를 사용하는 바운드 형식 블로킹 큐가 가득 실현으로 간주 코어/최대 스레드의 사용을 만들 수 있어야합니다. 따라서 10 개의 코어 스레드가 있고 11 번째 스레드가 11 번째 스레드를 시작하게하려면 불행하게도 0 크기의 블로킹 큐가 필요합니다 (아마도 SynchronousQueue). 나는 이것이 매우 위대한 ExecutorService 클래스의 실제 제한이라고 생각합니다.

1

세트 maximumPoolSize에서 Integer.MAX_VALUE. 20 억 개 이상의 스레드가 있다면 ... 그걸로 행운을 빈다.

어쨌든, ThreadPoolExecutor 국가의 자바 독 : Integer.MAX_VALUE 등의 원칙적으로 무제한 한 값으로 maximumPoolSize를 설정함으로써

, 당신은 풀이 임의의 수의 동시 태스크를 수용 할 수 있습니다. 가장 일반적으로, 코어 및 최대 풀 사이즈는 구축시에만 설정됩니다 만, setCorePoolSize (int) 및 setMaximumPoolSize (int)를 사용해 동적으로 변경할 수도 있습니다.

LinkedBlockingQueue과 같은 제한되지 않은 작업 대기열을 사용하면이 용량이 임의로 커집니다.

+0

downvoter는 설명해 주길 원합니까? –

+0

고마워 또한 이것을 참조하십시오 http://stackoverflow.com/questions/28567238/threadpoolexecutor-does-not-shrink-properly/40384042#40384042 다른 문제가 해결되었습니다. – Vahid

+0

그는 제한되지 않고 경계를 설정하고 싶습니다. .. – Xerus

8

성장과 축소가 스레드와 함께있을 때 내 머리에는 단 하나의 이름 만 있습니다. CachedThreadPool from java.util.concurrent package.

ExecutorService executor = Executors.newCachedThreadPool(); 

CachedThreadPool는() 스레드을 재사용뿐만 아니라 을 필요로 할 때 새 스레드를 생성 할 수 있습니다. 그리고 스레드가 60 초 동안 유휴 상태이면 CachedThreadPool이 스레드를 죽입니다. 이것은 매우 가볍습니다 - 당신의 말로 성장하고 줄어들고 있습니다!

+6

맞지만 경계가 없습니다. – Gray

+0

기본 ThreadPoolExecutor 및 setup maximumPoolSize를 수동으로 또는 런타임에 사용할 수도 있습니다. –