2017-09-04 2 views
2

SpringアプリケーションでグローバルThreadPoolTask​​Executorを作成する必要があります。これは、アプリケーションでマルチスレッドタスクを実行する責任があります。Java SpringのThreadPoolExecutorの制御

しかし、すべての要求に対して、そのグローバルThreadPoolから使用されるスレッドの数を制限する必要があります。要求ごとにこの制限が適用されることをどのように保証するべきですか?

たとえば、

最大プールサイズを50スレッドとしてグローバルスレッドプールを作成します。しかし、私はスレッドごとにスレッド数を5スレッドに制限したいと思っています。しかし、これら5つのスレッドは、コンフィグレーションファイルで定義されたグローバルスレッドプールで使用可能な50個のスレッドからのみ割り当てられます。

タスク実行プログラムを作成するための構成クラス。

@Configuration 
public class ThreadPoolConfiguration { 

    @Value("${threadpool.corepoolsize}") 
    int corePoolSize; 

    @Value("${threadpool.maxpoolsize}") 
    int maxPoolSize; 

    @Bean 
    public ThreadPoolTaskExecutor taskExecutor() { 
     ThreadPoolTaskExecutor pool = new ThreadPoolTaskExecutor(); 
     pool.setCorePoolSize(corePoolSize); 
     pool.setMaxPoolSize(maxPoolSize); 
     pool.setWaitForTasksToCompleteOnShutdown(true); 
     return pool; 
    } 
} 

コントローラクラス

@RestController 
public class WebController { 

    @Autowired 
    ThreadPoolTaskExecutor threadPool; 

    @RequestMapping("/process") 
    public String process(){ 

     String msg = ""; 
     List<Future<String>> futureList = new ArrayList<>(); 
     for(int threadNumber = 0; threadNumber < 5; threadNumber ++){ 
      CallableWorker callableTask = new CallableWorker(String.valueOf(threadNumber)); 
      Future<String> result = threadPool.submit(callableTask); 
      futureList.add(result); 
     } 

     for(Future<String> future: futureList){ 
      try { 
       msg += future.get() + "#####"; 
      } catch (Exception e){} 
     } 

     return msg; 
    } 
} 

免責事項:これは私がblog postからもらったばかりのサンプルコードです。

このようなデザインを実装するにはどうすればよいですか?作成できるサブスレッドプールはありません。また、すべての要求に対してスレッドプールをインスタンス化することは致命的な問題ではありません。

提案がありますか?

+0

リクエストに6つのタスクがあり、5つのスレッドに制限されている場合の動作は何ですか?最初の5つのタスクのいずれかが完了するまで待ってから、6番目のタスクをキューイングしますか? –

+0

はい、そうです。しかし、別のリクエストには5つのタスクがあり、グローバルスレッドプールから5つのスレッドを分けてください。 は、だから私は20回の作業を取得する場合: そして、2つの要求が提出された後に、グローバルプールからの10件のスレッドが占有され、1タスクは、これらは、私はあなたの答えから理解二つの解釈されている(最初のリクエストから)待って、まだ – Amriteya

答えて

1

これを解決する1つの方法は、単一の要素ではなく要素のリストを処理する呼び出し可能なメソッドを作成することです。

たとえば、リクエスト内のx個のアイテムを削除する場合は、x/5個の要素のリストを作成し、このリストを呼び出し可能な関数に渡すことができます。このようにして、コードを使用して、最大5つのスレッドしか要求ごとに使用されないようにすることができます。あなたは注意して例外シナリオを処理する必要があります。 (たとえば、結果が成功する可能性のあるresultID、または再試行可能な例外または再試行不可能な例外のelementIDのMapを返すことができます)。

このアプローチは、達成しようとしているものによって異なる場合があります。

+0

あります最初のリクエストでは、4つの項目のリストに分割します。 [1-5,6-10,11-15,16-20]、1-5を1つのジョブ(スレッド)として提出する。他の15人はどうなりますか? または、4つのスレッドすべてに4つのタスクグループを提出しますか?まず、5つ以上のタスク(例えば30)がある場合、どのように処理すればよいですか?次に、私のユースケースでは、スレッドごとに1つのタスクが必要です。だから私はスレッドに1つのグループを提出するとき、私は不要なオーバーヘッドをもたらすだけで1つの要求が一度に5つのスレッドを持つことができます私の最初の条件に違反するリードする並列化する必要があります。 – Amriteya

+1

リクエストが20件ある場合は、それぞれ4つの要素からなる5つのリストを作成し、この4つの要素をメソッドで順次処理します。リクエストが50件ある場合は、それぞれ10個の要素からなる5つのリストを作成し、10個の要素を順次処理します。あなたがここでやっているのは、タスクを並列に実行できる5つの小さなタスクに分解できるものに分割することです。 –

+0

アプローチは良いと思います。私が見る唯一の問題は、リストの反復を編成するために1つのスレッドをブロックすることです。そして、4つのジョブを提出し、4つのジョブを提出して終了するのを待つので、重い作業になります。 ThreadPoolTask​​Executorを使用することができれば、キュー内のすべてのジョブをサブミットしてそのスレッドを取得できます。私はキュー内のジョブを提出できるソリューションを探しています。 – Amriteya

0

これを行う方法は、タスクを抑制するクラスを作成することです。各リクエストはスロットルを作成し、すべてのタスクをスロットルに送信します。スロットルは最初の5つのタスクを実行者に提出し、他のタスクをリストに入れます。提出されたタスクが完了したので、追加のタスクを提出できます。

タスクが完了した時点を決定するために、スロットルは、提出されたタスクを定期的にポーリングし、FuturesのisDone()メソッドをチェックして完了したかどうかを確認するか、Futureのget()その時点で他の保留中の先物をチェックするか、洗練されたものにしたい場合は、要求スレッドはスロットルでwait()でき、タスクは完了時にスロットルを通知するように設定できます目を覚まして完了したタスクを確認してください。