Java スレッド プールの 8 つの主要な拒否戦略

写在前面

以前に「アリババがスレッド プールを作成するエグゼキュータを無効にする理由」という記事を書きましたが、この記事では、ThreadPoolExecutor の作成には 7 つのパラメータがあり、そのうちの 1 つはパラメータ RejectedExecutionHandler であり、設定の拒否戦略であると述べられています。スレッドプール。拒否戦略は、コア スレッドの数、ブロックしているキューの数、およびスレッドの最大数がすべて上限に達した場合に発生します。
JDK には 4 つのスレッド プール拒否戦略がプリセットされていますが、これらの戦略の使用シナリオとシナリオを組み合わせて、どのような拒否戦略を拡張できるかを詳しく説明します。

本文内容

  • 拒否ポリシーインターフェイス定義
  • CallerRunsポリシー
  • ポリシーの中止
  • ポリシーの破棄
  • 最も古いポリシーを破棄
  • dubbo のスレッド拒否ポリシー
  • Netty のスレッド プール拒否ポリシー
  • activeMq でのスレッド プールの拒否戦略
  • ピンポイントでのスレッドプール拒否ポリシー

拒绝策略接口定义

jdk によって提供される 4 つの拒否戦略はすべて RejectedExecutionHandler インターフェイスを実装します。このインターフェイスの定義を見てみましょう。
ここに画像の説明を挿入
インターフェイスの定義は非常に単純で、メソッドが 1 つだけです。拒否戦略がトリガーされると、スレッド プールは設定した特定の戦略を呼び出し、現在送信されているタスクとスレッド プールを渡します。インスタンス自体は処理のためにあなたに提供されます。具体的にどのように対処するか、シナリオによって考慮すべき点も異なります
。それでは、JDK がどのような実装を組み込んでいるかを見てみましょう。

CallerRunsPolicy

ここに画像の説明を挿入
機能: 拒否ポリシーがトリガーされると、スレッド プールが閉じられていない限り、タスクを送信した現在のスレッドによって処理されます。
使用シナリオ: 通常、スレッド プールは通常の状況では閉じられないため、つまり、送信されたタスクは確実に実行されるため、失敗が許されず、パフォーマンス要件が高くなく、同時実行性が小さいシナリオで使用されます。ただし、呼び出し元であるため、スレッド自体が実行され、タスクが複数回送信されると、後続のタスクの実行がブロックされ、当然パフォーマンスと効率が低下します。

AbortPolicy

ここに画像の説明を挿入
機能: 拒否ポリシーがトリガーされると、実行を拒否する例外が直接スローされ、現在の実行プロセスが中断されます
使用シナリオ: これには特別なシナリオはありませんが、スローされた例外を正しく処理することが 1 つあります。
ThreadPoolExecutor では默认的策略就是AbortPolicy、 ExecutorService インターフェースの ThreadPoolExecutor 系列には表示拒否ポリシーがないため、デフォルトはこれです。ただし、ExecutorService のスレッド プール インスタンス キューは無制限であることに注意してください。つまり、メモリが爆発した場合、拒否ポリシーはトリガーされません。スレッド プール インスタンスを自分でカスタマイズする場合、このストラテジの使用時にストラテジがトリガーされたときにスローされる例外を処理する必要があります。これは、現在の実行プロセスが中断されるためです。

DiscardPolicy

ここに画像の説明を挿入
機能: 拒否ポリシーが発生しても、アクションはトリガーされません。
使用シナリオ: 送信したタスクが無関係であれば、それを使用できます。これは単なる空の実装であるため、静かにタスクを消費します。したがって、この戦略は基本的に役に立ちません

DiscardOldestPolicy(弃老策略)jdk

ここに画像の説明を挿入
機能: スレッド プールが閉じられていない場合は、キューの先頭にある要素をポップアップし、
使用シナリオの実行を試みます。この戦略でもタスクは破棄され、破棄時にサイレントになりますが、特徴は次のとおりです。古い未実行のタスクを破棄し、より優先度の高いタスクを実行することを意味します。この機能に基づいて、私が考えることができるシナリオは、メッセージを公開し、メッセージを変更することです。メッセージが公開された時点では、メッセージはまだ実行されていません。このとき、更新されたメッセージが再び来ます。このとき、のバージョンは、未実行のメッセージは現在送信されたメッセージよりも上位です。バージョンが低い場合は、破棄できます。実行のためにキューに入れられるキューには、メッセージ バージョンが低いメッセージが存在する可能性があるため、実際にメッセージを処理する際には、メッセージ バージョンを適切に比較する必要があります。

上記は jdk に付属する 4 つの拒否戦略であり、比較的シンプルで一目で理解できます。
サードパーティが実行する拒否戦略を見てみましょう

dubbo中的线程拒绝策略

ここに画像の説明を挿入
dubbo の作業スレッドがスレッド拒否をトリガーするとき、主に 3 つのことを行うことがわかります。原則として、スレッド拒否ポリシーをトリガーする本当の理由をユーザーに知らせようとすることです。1. 警告付きのログを出力します。レベル、ログの内容は
スレッドです。 プールの詳細な設定パラメータ、スレッド プールの現在の状態、および現在拒否されているタスクの詳細。このログは、dubbo を使用したことがある方や運用保守の経験がある方であれば、多かれ少なかれ目にしたことがあるログだと言えますが、このログは単なるログ出力のモデルであり、他のログ出力のモデルには spring などがあります。このような詳細なログのおかげで、問題を特定するのが簡単です;
2. 現在のスレッドスタックの詳細を出力します。 3.拒否例外をスローし
続けて、このタスクを失敗させます。これは、JDK のデフォルトの拒否戦略の特性を継承します。

Netty中的线程池拒绝策略

ここに画像の説明を挿入
Netty の実装は、タスクを破棄することを躊躇する JDK の CallerRunsPolicy に非常に似ています。違いは、CallerRunsPolicy が呼び出し側スレッドで直接実行されるタスクであることです。そして、Netty はそれを処理するための新しいスレッドを作成します。したがって、Netty の実装は、呼び出し元の実行戦略の使用と比較して、高効率および高パフォーマンスのシナリオをサポートするように拡張できます。ただし、Netty の実装では、スレッドの作成時に判断制約が行われないことにも注意してください。つまり、システムにまだリソースがある限り、新しいスレッドが作成され、新しいスレッドが生成されなくなるまで、それらを処理するための新しいスレッドが作成されます。スレッドの作成に失敗した例外

activeMq中的线程池拒绝策略

ここに画像の説明を挿入
activeMq の戦略はベストエフォート実行戦略に属しており、拒否戦略がトリガーされると、一度に 1 分間全力で実行されます。1 分間のタイムアウトに失敗した場合にタスクをタスク キューに再投入し、ピンポイントで例外をスローする
pinpoint中的线程池拒绝策略
ここに画像の説明を挿入
拒否戦略の実装は非常に特徴的であり、他の実装とは異なります。彼は、拒否戦略リストをラップする拒否戦略チェーンを定義し、拒否戦略がトリガーされると、戦略チェーン内の拒否された実行が順番に実行されます。

この記事の内容のほとんどは、https://my.oschina.net/keking/blog/3080826 から引用しています
。ありがとうございます。

おすすめ

転載: blog.csdn.net/u010994966/article/details/103188858