Javaスレッドプールの拒否ポリシー

5580 ワード

一、紹介
  jdk1.5バージョンにはJUC同時プログラミングパッケージが追加され、従来のマルチスレッド開発を大幅に簡素化しました.スレッドプールの使用、リンクアドレスについては、前の記事で説明しました.https://www.cnblogs.com/eric-fang/p/9004020.html
Javaスレッドプールは、典型的なプール化思想の産物であり、データベースの接続プール、redisの接続プールなどがある.プール化思想は、最初にリソースを申請し、使用可能な接続を作成することであり、使用するときに接続情報の作成にオーバーヘッドする必要がなくなります.生活の中で鮮明な例を挙げると、有名な洋食ファーストフードの某基や某労に行くとき、配膳員は真ん中の保温箱から直接食材を取り、梱包すればいいのです.一時的にリストを1つ来なくてもいいし、原材料を取りに行ったり、加工したりします.効率が明らかに向上した.
満ち足りて損をしないとあふれ、満ち足りて持たないと傾くと言われています.スレッドプールがコンテナである以上,必然的に満タンになることがある.何か特定の条件に達したときに、またリクエストをすると、池はどのようにリクエスト処理を行っているのでしょうか.ここではプールの拒否ポリシーを引き出します.一般的なデータベース接続プールでは、最大接続数に達すると、デフォルトで特定の設定を待つ時間、または直接例外が放出されます.ここで説明するスレッドプールはそうではありません.次に説明します.
二、スレッドプールの拒否ポリシー
スレッドプールには、3つの重要なパラメータがあり、corePoolSize-コアスレッド数、すなわち最小スレッド数に影響を及ぼすことを決定します.WorkQueue-キューをブロックします.maximumPoolSize-最大スレッド数
コミットされたタスク数がcorePoolSizeより大きい場合は、ワークキューに優先的にタスクが配置されます.ブロックキューが飽和すると、maximumPoolSizeの最大スレッド数構成に達するまでスレッドプール内のスレッド数が拡張されます.この場合、さらに余分なタスクが発生すると、スレッドプールの拒否ポリシーがトリガーされます.
まとめると、コミットされたタスク数が(workQueue.size()+maximumPoolSize)より大きい場合、スレッドプールの拒否ポリシーがトリガーされます.
三、ポリシー定義の拒否
拒否ポリシーは、メソッドrejectedExecution、すなわち特定の拒否ポリシーの実行ロジックをカスタマイズするトップレベルのインタフェースRejectedExecutionHandlerを提供します.
jdkのデフォルトでは、4つの拒否ポリシーが提供されています.
CallerRunsPolicy-スレッドプールが閉じていない限り、コールスレッドを使用してタスクを直接実行する拒否ポリシーがトリガーされます.通常、コンカレントは比較的小さく、パフォーマンス要件は高くなく、失敗は許されません.ただし、呼び出し元が自分でタスクを実行するため、タスクのコミット速度が速すぎると、プログラムがブロックされ、パフォーマンス効率上の必然的な損失が大きい可能性があります.
AbortPolicy-タスクを破棄し、RejectedExecutionException例外の実行を拒否する情報を放出します.スレッドプールのデフォルトの拒否ポリシー.投げ出された例外を処理する必要があります.そうしないと、現在の実行プロセスが中断され、後続のタスクの実行に影響します.
DiscardPolicy-直接捨てて、他に何もありません
DiscardOldestPolicy-スレッドプールが閉じていない限り、ブロックキューworkQueueで最も古いタスクを破棄し、新しいタスクを追加する拒否ポリシーがトリガーされます.
四、テストコード
  1、AbortPolicy 
package com.cfang;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import lombok.extern.slf4j.Slf4j;

@Slf4j
public class T2 {

    public static void main(String[] args) throws Exception{
        int corePoolSize = 5;
        int maximumPoolSize = 10;
        long keepAliveTime = 5;
        BlockingQueue workQueue = new LinkedBlockingQueue(10);
        RejectedExecutionHandler handler = new ThreadPoolExecutor.AbortPolicy();
        ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, TimeUnit.SECONDS, workQueue, handler);
        for(int i=0; i<100; i++) {
            try {
                executor.execute(new Thread(() -> log.info(Thread.currentThread().getName() + " is running")));
            } catch (Exception e) {
                log.error(e.getMessage());
            }
        }
        executor.shutdown();
    }
}

   executor.execute()タスクをコミットすると、tryがない場合はRuntimeExceptionが投げ出されます.catchが異常情報を処理すると,呼び出し者の処理フローが中断され,後続タスクが実行されない(100個未満).自分でテストできるので、コンソールコンソールコンソールで簡単に表示できます.
  2、CallerRunsPolicy 
マスターコードと同じで、拒否ポリシーを交換します.
RejectedExecutionHandler handler = new ThreadPoolExecutor.CallerRunsPolicy();

実行後、コンソールコンソールコンソールに表示されるのは、一部のデータが印刷され、「main is running」、すなわち呼び出しスレッド処理が表示されます.
  3、DiscardPolicy 
拒否ポリシーの交換
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardPolicy();

直接タスクを破棄し、実際の実行中に印刷された情報は100件もありません.
  4、DiscardOldestPolicy 
同様に、拒否ポリシーを交換します.
RejectedExecutionHandler handler = new ThreadPoolExecutor.DiscardOldestPolicy();

実際に実行すると、印刷された情報も100個未満になります.
五、まとめ
4つの拒否ポリシーは互いに独立していないので、どのポリシーを選択して実行するかは、具体的なビジネスシーンと結びつけなければなりません.実際の作業では、ExecutorServiceを直接使用する場合、デフォルトのdefaultHandler、すなわちAbortPolicyポリシーが使用されます.