Alibaba プロトコルはスレッド プールを手動で作成しますが、Executor を使い続けるのはなぜですか?

事前告知

タイトルはセンセーショナルなものを意図したものではなく、実際に Executor を使用してスレッド プールを作成しています。この記事では、スレッド プールのパラメーター、スレッドのステータス、その他の概念については詳しく説明しません。

Alibaba がスレッド プールを手動で作成することの深い意味は知っていますが、ThreadPoolExecutor を通じてスレッド プールを作成すると、ユーザーはスレッド プールの運用ルールを明確にし、リソース枯渇のリスクを回避できます。

リソース枯渇のリスク

リソース枯渇のリスクは主にメモリに起因します。

1. Executors.newFixedThreadPool および Executors.newSingleThreadExecutor によって作成されたスレッド プールを使用すると、待機キューのデフォルト値は Integer.MAX_VALUE になり、これは基本的に無制限のキューと同等です。

特に集中的なコンピューティング タスクの場合、スレッド数が明確に制限されていることは間違いありません。スレッド数の設定が高すぎると、スレッドの消費量が増加するだけであり、タスクの実行効率は向上しません。リクエストの量が多すぎると、キューに大量のリクエストデータが蓄積され、OOM が発生する可能性が高くなります。

2. Executors.newCachedThreadPool および Executors.newSingleThreadScheduledExecutor を使用して作成されたスレッド プールの場合、スレッドの最大数は Integer.MAX_VALUE であり、これは基本的に無限と同等です。

大量のリクエストと無制限のスレッド作成の場合、ThreadStackSize は 1024k と計算され、OOM が発生する可能性が非常に高くなります。

スレッド プールを作成するために Executor を使用するのはなぜですか

理由は 2 つあります。

1. 私はあらゆる種類のルールや規制が好きではありません。Java には、Java エコシステム自体を含め、すでに多くの規制があります。Ali による別の規制が必要ですか?

2. Java にはこのようなスレッド プール ツールが付属しているので、便利なはずです。

私の個人的な意見では、Executor を使用することと ThreadPoolExecutor を直接使用することの間に本質的な違いはありません。タスク自体にもっと注意を払う必要があります。

Executor を使用して作成されたスレッド プールに OOM が発生すると仮定すると、ThreadPoolExecutor を使用してそれを回避できますか? 答えはおそらくノーです。

スレッド プールを使用する場合のいくつかの考慮事項

私は通常、次のことを考えることから始めます。

1. タスクは IO ですか、それとも計算ですか?

2. 通常、プログラム スレッド プールは、小規模および大規模なバッチ タスクを処理するために使用されます。

3. スレッドの数は CPU コアの数に対応します

4. リクエストの量とサイズ

5. スレッド プールの現在の実行ステータスを定期的に監視します。

6. スレッド数を動的に設定可能

7. 適切な制御スレッド数

8. タスクに時間がかかる場合は、分割または最適化を試みます

シナリオの仮定

まずシナリオを見てみましょう。A が規模 1 億、ペイロード 100B でデータを B にプッシュし続けるとします。B がデータを受信して​​応答した後、A はデータを B にプッシュし続けます。データのプッシュに影響を与えないように、B は直接応答し、スレッド プールは A によってプッシュされたデータを非同期に処理します。

仮定のシナリオはちょっと味気ないかもしれませんが、現実にはそういうシナリオもあるので、まあ許容範囲で。

Executors.newFixedThreadPool を使用して 10 スレッドのスレッド プールを作成するとします。単一のスレッドがタスクを実行するのに 10 ミリ秒かかります。考えてみてください。5 分後に、スレッド プールは 10 100 300 個のタスクを処理しました。スレッド切り替え、累積プロセス 300,000 タスク。

キューには約 1 億件のデータが残っています。100B*100000000/1024、約 9g のデータ、完全に OOM。

問題の根本原因

ここで疑問が生じます。ThreadPoolExecutor を使用する場合、いくつのスレッドを開けばよいでしょうか? キューはどのくらいの大きさにすべきでしょうか? データが到着すると、スレッドはいっぱいになり、キューもいっぱいになり、データは直接破棄されますか? それともビジネス スレッド自体は実行を継続しますか?

現時点では、スレッドは基本的にビジー状態であり、CPU は競合しており、メモリは OOM です。

現状を分析し、課題を解決する

明らかに、この時点では、むやみにスレッド プールに送信するのではなく、速度を下げる必要があります。

上記の点に基づいて、このプログラム フローを再最適化してみましょう。

1. タスクは計算指向です。4 コアで 10 スレッドを開くのが妥当です。デバッグ前にスレッド数を動的に設定できます。

2. リクエストの合計サイズは約 10g です。8g のメモリを搭載したアプリケーションの場合、1g のメモリと約 10,000 のタスク データを占有することを考慮してください。

3. Executors.newSingleThreadScheduledExecutor を使用して、スレッド プールのステータスを定期的に監視します。

上記の頭の悪い分析に対して

1. Executors.newFixedThreadPool と Executors.newSingleThreadScheduledExecutor を使用しており、前者はタスクの実行に使用され、後者はスレッド プールの状態を定期的に出力するために使用されます。

2. B 側は A 側とネゴシエートし、毎回 1,000 個のデータをプッシュし、10 スレッドで 10,000 個を処理します。セマフォを使用してデータを厳密に制御し、データはキューに入らないようにします。または、セマフォ制御が使用されます。 、キューには最大 10,000 個のデータしか入力できません。セマフォのサイズは 10000+ スレッドの場合です。

3. スレッド プールの最大スレッド数を動的に設定し、スレッド プールの状態を定期的に監視する魔法はありませんが、スレッド プールはそのような方法を提供します。

要約する

以上が本稿で詳述する観点であるが、主に次の点を言いたい。

1. いかなる規制にも盲目的に従わない

2. ビジネスデータにできる限り注意を払う

3. スレッドプールの合理的な使用

役に立ったと思ったらフォローしてください、気に入ったらフォローしてください。

同名の公開アカウント [Mainongmai]

おすすめ

転載: blog.csdn.net/weixin_43275277/article/details/125857510