18

Java(java.util.concurrent)にスレッドプールを実装する必要があります。このスレッドプールのスレッド数は、アイドル時に最小値になり、ジョブが実行を終了するよりも速く送信されると、上限まで増加します(ただし、それ以上になることはありません)。 、およびすべてのジョブが完了し、それ以上ジョブが送信されなくなると、下限に縮小します。

そのようなものをどのように実装しますか?これはかなり一般的な使用シナリオになると思いますが、java.util.concurrent.Executorsファクトリメソッドで作成できるのは、固定サイズのプールと、多くのジョブが送信されたときに無制限に大きくなるプールのみです。ThreadPoolExecutorクラスはパラメータを提供しcorePoolSizeますmaximumPoolSizeが、そのドキュメントは、同時に複数のスレッドを持つ唯一の方法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ジョブが終了するまで上記のコードが終了しないという問題が発生する可能性があります。したがって、任意の数のジョブをプールに送信して、それらのいずれかが終了するのを待たずにすぐに続行できるようにしたい場合、管理する専用の「ジョブサミット」スレッドがなければ、それを行う方法がわかりません。送信されたすべてのジョブを保持するために必要な無制限のキュー。AFAICS、ThreadPoolExecutor自体に無制限のキューを使用している場合、そのスレッド数がcorePoolSizeを超えることはありません。

4

3 に答える 3

13

成長と縮小がスレッドと一緒になるとき、私の頭に浮かぶ名前はjava.util.concurrentパッケージのCachedThreadPoolだけです。

ExecutorService executor = Executors.newCachedThreadPool();

CachedThreadPool()は、スレッドを再利用できるだけでなく、必要に応じて新しいスレッドを作成できます。はい、スレッドが60秒間アイドル状態の場合、CachedThreadPoolはスレッドを強制終了します。つまり、これは非常に軽量です–言葉で言えば、成長と縮小です!

于 2012-06-28T17:40:38.537 に答える
6

役立つ可能性のあるトリックの1つRejectedExecutionHandlerは、同じスレッドを使用するを割り当てて、ジョブをブロッキングキューに送信することです。これにより、現在のスレッドがブロックされ、ある種のループが不要になります。

ここで私の答えを参照してください:

処理する必要のあるデータが多すぎる場合、ThreadPoolExecutorコマンドを待機させるにはどうすればよいですか?

これがその回答からコピーされた拒否ハンドラーです。

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これは、他の点では素晴らしいクラスの本当の制限だと思います。

于 2012-06-28T16:58:31.650 に答える
1

に設定maximumPoolSizeInteger.MAX_VALUEます。20億を超えるスレッドがある場合は、幸運を祈ります。

とにかく、JavadocのThreadPoolExecutor状態:

maximumPoolSizeをInteger.MAX_VALUEなどの本質的に無制限の値に設定することにより、プールが任意の数の同時タスクに対応できるようにします。最も一般的には、コアと最大プールサイズは構築時にのみ設定されますが、setCorePoolSize(int)とsetMaximumPoolSize(int)を使用して動的に変更することもできます。

のような同様に無制限のタスクキューではLinkedBlockingQueue、これは任意に大きな容量を持つ必要があります。

于 2012-06-28T16:58:41.967 に答える