2013-08-08 9 views
6

ExecutorServiceを使用して、さまざまなスレッドで多くのタスクを実行します。 スレッドプール内で待機中のRunnableインスタンスが多すぎると、Out of Memoryの問題が発生することがあります。ExecutorServiceのスレッドをどのように制限しますか?

私はそれを解決するためにブロックジョブエグゼキュータを書きます。それを行うための公式な解決策はありますか?例えば

:ここ

BlockingJobExecutor executor = new BlockingJobExecutor(3); 
    for (int i = 0; i < 1000; i++) { 
     executor.addJob(new Runnable() { 

      @Override 
      public void run() { 
       try { 
        Thread.sleep(1000); 
       } catch (InterruptedException e) { 
        e.printStackTrace(); 
       } 
       LogFactory.getLog(BTest.class).info("test " + System.currentTimeMillis()); 
      } 
     }); 
    } 
    executor.shutdown(); 

はBlockingJobExecutorクラスです:

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.TimeUnit; 
import java.util.concurrent.atomic.AtomicInteger; 

public class BlockingJobExecutor { 

    AtomicInteger counter = new AtomicInteger(); 
    ExecutorService service; 
    int threads; 

    public BlockingJobExecutor(int threads) { 
     if (threads < 1) { 
      throw new IllegalArgumentException("threads must be greater than 1."); 
     } 
     service = Executors.newFixedThreadPool(threads); 
     this.threads = threads; 
    } 

    static class JobWrapper implements Runnable { 
     BlockingJobExecutor executor; 
     Runnable job; 

     public JobWrapper(BlockingJobExecutor executor, Runnable job) throws InterruptedException { 
      synchronized (executor.counter) { 
       while (executor.counter.get() >= executor.limit()) { 
        executor.counter.wait(); 
       } 
      } 
      this.executor = executor; 
      this.job = job; 
     } 

     @Override 
     public void run() { 
      try { 
       job.run(); 
      } finally { 
       synchronized (executor.counter) { 
        executor.counter.decrementAndGet(); 
        executor.counter.notifyAll(); 
       } 
      } 
     } 
    } 

    public int limit() { 
     return threads; 
    } 

    public void shutdown() { 
     service.shutdown(); 
     try { 
      service.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS); 
     } catch (InterruptedException e) { 
      throw new RuntimeException(e); 
     } 
    } 

    public void addJob(Runnable job) { 
     try { 
      service.execute(new JobWrapper(this, job)); 
     } catch (InterruptedException e) { 
      throw new RuntimeException(e); 
     } 
    } 

} 
+0

実行待ちのジョブが多すぎるか、あまりにも多くのスレッドが同時に実行されていることを意味しますか? – chrylis

+0

実行待ちジョブが多すぎます。 – qrtt1

答えて

12

これが起こることができる2つの方法があります。実行待ちのキューに入っている実行可能ファイルが多すぎるか、同時に実行されているスレッドが多すぎる可能性があります。キューに入れられたジョブが多すぎる場合は、ExecutorServiceの固定サイズBlockingQueueを使用して、キューに入れることができるアイテムの数を制限できます。新しいタスクをキューに入れようとすると、キューに空きがあるまで操作はブロックされます。

一度に実行するスレッドが多すぎる場合は、ExecutorServiceでタスクを実行するために使用できるスレッドの数を、スレッド数を指定してExecutors.newFixedThreadPoolと指定することで制限できます。

関連する問題