ホームページ  >  記事  >  Java  >  Javaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?

Javaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?

PHPz
PHPz転載
2023-05-09 19:10:061165ブラウズ

1. スレッドとスレッド プールとは

スレッドは、オペレーティング システムにおけるタイミング スケジューリングの基本単位です。

スレッド プールは、スレッドを含むプール (コンテナー) として理解できます。このコンテナーにはスレッドのみを含めることができます。この容器にはさまざまなサイズがあり、7個または8個、または3個または4個を保持できます。コンテナーを埋めることもできますが、最大値 (12 など) があります。たとえば、ここのスレッド プールには通常 5 つのスレッドが含まれており、最大 12 個のスレッドを含めることができます。この時点で、スレッド プールを使用する必要がある人が 5 人いたため、彼は 5 つのスレッドを奪いました。後から 2 人が来たらどうなるでしょう? 彼には使用するスレッドがまったくなかったので、その 5 人が使い終わるまで待たなければなりませんでした。それ。しかし、私のプールには 12 を保持できます。スレッドが 5 つしかない場合、どうすればよいでしょうか? 間違いなく、さらにいくつかのスレッドをインストールする必要があります。そうしないと、もっと人がいると十分ではありません。この時点では、2 が来ました、そして2 つ作成しています。スレッドの総数は 7 になります。この時点で、残りの 2 人は待つ必要がなく、直接使用できます。 6 人が来た場合、現時点では、私のプールには 5 スレッド分の容量しかない可能性があり、5 つのスレッドを生成できますが、まだ 1 人がどこかで待たなければなりません。むやみに待たせるわけにはいきません。椅子を 5 つ見つけます。そこに座って待っていてください。すると、最初の 5 人のグループのスレッドがなくなり、突然 5 つのスレッドが空きます。残りの 1 人が使用できます。スレッドです。この時点で、さらに 10 人が次々に来ました。私のスレッドは 4 人しか利用できません。席は 5 人座れます。1 人残っていたらどうすればいいですか? または直接拒否してください。私はしません」最初に他を探さずに断るのは確かに不快ですし、いくつかの拒否戦略を考えなければなりません。 。 。 , まだ多くの人が私のスレッド プールを使用していると思います。非常に多くの人が使用しているので、誰かが私のスレッド プールを占有し続けたらどうなりますか?それに対処する方法を見つけなければなりません。それ以外の場合、1 つのスレッドは 1 分間しか使用できず、使用後すぐにリサイクルされるため、再度使用したい場合はキューに並んで再度待ちます。このようにして、私の糸ビジネスはますます良くなり、誰かがそれを使用する限り、糸は走り続けます。

レストランかビュッフェのお店に似ていますか? ビュッフェのお店の方が視覚的です。私のホテルでは、席さえあれば座ることができます。最大収容人数に達すると、残った客は入り口で待つしかない、店内にいる客が来て外で待つ、待つスペースがなくなったら、客はスペースがないと判断して直接退店する、どうしても食べたい人がいると、彼らはもう少し待つことができます。レストラン内でのお客様は、長時間(通常は席がない場合)約 2 時間ほど食事をしないでください。食べたら席を外してください。

上記の説明に基づいて、スレッド プールに何が入っているかを判断できると思います。

インストールされるスレッドの数、インストールできるスレッドの数、スレッドを保持できる期間、スレッド待機領域、拒否方法、スレッドの作成

Javaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?

#1.1、スレッドを使用する理由

プログラムの実行はプロセスに依存する必要があり、プロセスの実際の実行単位はスレッドです。

  • システム内のサービスの呼び出し。システムはプロセスの実行に依存しています。システム内には多くのサービスがあり、サービス間の相互作用が存在します。サービスの実行はスレッドに依存しています。マルチサービス操作はマルチスレッド操作に依存します。サービス間の呼び出しとデータ交換は、データ対話のためにプロセス間のメモリに依存しますが、同時にスレッドは独自のメモリ空間を構築することもできます。リソースのスケジューリングとプロセス間のデータ対話に依存します。

  • マルチスレッドにより、プログラムの実行パフォーマンスが向上します。たとえば、90平方メートルの家がある場合、1人で掃除すると30分かかりますが、3人で掃除すると10分しかかかりません。この3人がプログラムの「マルチスレッド」です。

多くのプログラムでは、作業を並行して完了するには、複数のスレッドを相互に同期するか、相互に排他的に同期する必要があります。

スレッドはプロセスよりも軽量であるため、スレッドの作成と破棄のコストが小さくなります。

スレッドはパフォーマンスを向上させます。スレッドは巨視的には並列ですが、微視的には直列です。 CPU の観点からは、スレッドによってパフォーマンスを向上させることはできませんが、一部のスレッドがリソースの待機 (IO、入力の待機など) に関与している場合、マルチスレッドにより、プロセス全体がブロックされるのではなく、プロセス内の他のスレッドが実行を継続できるようになります。 CPU 使用率が向上するため、この観点からパフォーマンスが向上します。

複数の CPU またはマルチコアの場合、スレッドの使用は巨視的に並列であるだけでなく、微視的にも並列です。

1.2. スレッド プールを使用する理由

マルチスレッドはプログラムの実行パフォーマンスを向上させることができます

  • たとえば、ビュッフェを食べるとき、十分な座席数がある場合、ビュッフェは最も収益性が高く、食事料金と顧客満足度も向上します。 200 人が食事をしていて、100 か所の食事場所があり、1 人が平均 1 時間食事をするとすると、200 人は 2 時間で食事を終えることになります。 10席しかない場合、200人が食事をするには約20時間かかりますが、残りの客が心配して待っていればどんなに不幸になるか考えてみましょう。

  • ビュッフェの座席はスレッドです。スレッドが十分にあれば、より多くの人が食べることができます。ただし、スレッドが多ければ多いほど良いというわけではありません。結局のところ、必ずしも 200 席あるとは限りませんたとえ 200 人の顧客が食事をしに来たとしても、レストランに十分なシェフがいるかどうか、掃除婦が掃除できるかどうか、レストランに十分な皿があるかどうかなど、基本的なハードウェア要素を評価する必要があります。これは、メモリや CPU 処理などの重要なハードウェア条件を必要とするシステム構成に相当します。

スレッドの作成/破棄にはシステム オーバーヘッドが伴います。スレッドの作成/破棄を頻繁に行うと、処理効率に大きな影響を及ぼします (スレッドが実行され続ける限り、スレッドは破棄されません)

  • スレッドの作成には時間 T1 がかかり、タスクの実行には時間 T2 がかかり、スレッドの破棄には時間 T3 がかかることに注意してください。T1 T3>T2 の場合、コストがかからないことを意味しますか?このタスクを実行するためにスレッドを開くのは効果的ですか?たまたま、スレッド プールがスレッドをキャッシュし、既存のアイドル スレッドを使用して新しいタスクを実行できるため、T1 T3 によって引き起こされるシステム オーバーヘッドが回避されます。もちろん、残っているコア スレッドも CPU リソースを消費します

#同時実行スレッドが多すぎると、システム リソースが占有され、ブロックが発生します。

  • スレッドがシステム リソースを共有できることはわかっています。同時に実行されるスレッドが多すぎると、ブロッキングの場合、スレッド プールを使用すると同時スレッドの最大数を効果的に制御でき、上記の問題を回避できます。

スレッドの簡単な管理を実行します

  • 例: 遅延実行、タイミングループ実行戦略などはすべて、スレッド プールを使用して適切に実装できます

1.3. スレッド プールの利点

スレッド使用率の向上

  • 用事があるときはスレッドを使用し、用がないときは解放するようにして、リソースの無駄を避けるためにスレッドを合理的に使用します。

    ##プログラムの応答速度の向上

スレッドプールで一元管理している場合、統合スケジューリングプールを使用してリソースの割り当てをスケジュールします。スレッドを直接使用すると、時間のかかるスレッドの作成と破棄を回避できます。
  • スレッド オブジェクトの統合管理を容易にする

スレッド プールにより、スレッドの割り当てと管理を統合できます。
  • 同時実行の最大数を制御可能

サーバーにはスレッド使用量の上限があり、スレッド使用量も多くのリソースを消費しますしたがって、スレッド プールはスレッド リソースを非常に適切に制御し、無駄を避けることができます。
  • 2. java でのスレッド プールの使用
ThreadPoolExecutor クラスは、スレッドをプールするために使用できる Java のスレッド プール クラスです。

// 根据上面的描述大概分析一下线程都需要什么及参数的解析
// corePoolSize 核心线程数,就是上面说的装了多少个线程
// maximumPoolSize 最大线程数,就是上面说的能装多少线程
// keepAliveTime 存活时间,就是上面说的线程可以保留多长时间
// TimeUnit 这个是时间单位,有时、分、秒、天等等,是存活时间的单位
// BlockingQueue<Runnable> 这是一个等待队列,就是上面显示的线程等待区
// ThreadFactory 线程工厂,就是上面描述的如何创建线程,由谁创建
// RejectedExecutionHandler 拒绝策略,就是上面显示的如何拒绝,是直接拒绝还是婉拒
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler)
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)

ご覧のとおり、次のパラメータが必要です。 Javaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?

##corePoolSize (必須): コア スレッドの数。デフォルトでは、コア スレッドは常に存続しますが、allowCoreThreadTimeout が true に設定されている場合、コア スレッドもタイムアウトしてリサイクルされます。

  • maximumPoolSize (必須): スレッド プールが収容できるスレッドの最大数。アクティブなスレッドの数がこの値に達すると、後続の新しいタスクはブロックされます。

  • keepAliveTime (必須): スレッドのアイドル タイムアウト。この時間を超えると、非コアスレッドがリサイクルされます。 allowCoreThreadTimeout が true に設定されている場合、コア スレッドもタイムアウトになり、リサイクルされます。

  • unit (必須): keepAliveTime パラメーターの時間単位を指定します。一般的に使用されるものは、TimeUnit.MILLISECONDS (ミリ秒)、TimeUnit.SECONDS (秒)、TimeUnit.MINUTES (分) です。

  • workQueue (必須): タスクキュー。スレッドプールのexecute()メソッドを通じて送信された実行可能オブジェクトは、このパラメータに保存されます。ブロッキングキューを使用して実装されます。

  • threadFactory (オプション): スレッド ファクトリ。スレッド プールに新しいスレッドを作成する方法を指定するために使用されます。

  • ハンドラー (オプション): 拒否ポリシー。スレッドの最大数に達したときに実行する必要がある飽和戦略。

  • 2.1. スレッド プールの動作原理

2.2. スレッド プールの Java コード例

import java.util.concurrent.*;
public class ThreadTest {
    public static void main(String[] args) {
        ExecutorService threadPoolExecutor = new ThreadPoolExecutor(3, 5, 1L, TimeUnit.SECONDS, new ArrayBlockingQueue<>(3), Executors.defaultThreadFactory());
        for (int i = 0; i < 20; i++) {
            int finalI = i;
            threadPoolExecutor.submit( ()->{
                System.out.println(Thread.currentThread().getName() + "========" + finalI);
            });
        }
        threadPoolExecutor.shutdown();
    }
}
Javaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?実行結果:###

プール-1-スレッド-1========0
プール-1-スレッド-3========2
プール-1-スレッド- 3========4
プール-1-スレッド-2========1
プール-1-スレッド-3========5
プール-1-スレッド-2========8
プール-1-スレッド-5========7
プール-1-スレッド-1==== ====3
pool-1-thread-4========6
スレッド「メイン」での例外 java.util.concurrent.RejectedExecutionException: タスク java.util.concurrent.FutureTask@ 61e717c2 が java.util.concurrent.ThreadPoolExecutor@66cd51c3 から拒否されました [実行中、プール サイズ = 5、アクティブなスレッド = 2、キューに入れられたタスク = 0、完了したタスク = 7]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution (ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:112)
at com.halo.communication.ThreadTest.main(ThreadTest.java:10)

実行中の回線数スレッド 5 までの実行中のスレッドは、スレッド セルの許容サイズを超えて承認されたスレッドの実行を禁止し、その後、循環処理を開始します。

以上がJavaスレッドプールの原理、使い方、パフォーマンス最適化方法とは何ですか?の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はyisu.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。