原則の使用から、Javaスレッド・プールを探索します

スレッドプールとは何ですか

私たちは、タスクを処理する必要があるときは、スレッドがタスクを実行できるように、新しいスレッドを作成することができます。スレッドプールのストレージプールは、私たちが仕事に対処する必要がある場合、あなたは実行のためのスレッドプールからスレッドを削除することができ、スレッドの文字通りの意味です。

なぜ我々は、スレッドプールが必要なのか

まず第一に、我々はないスレッドプールのスレッドは直接の欠点ものを作成知っておく必要があります。

  1. 最初は、Javaスレッドは、スレッドの作成および破壊のオペレーティングシステムスレッドにシステム性能の大幅頻繁な損失にマッピングされ、作成および破壊オーバーヘッドスレッドです。

  2. スレッドは、我々が同時にタスクを実行するために多数のスレッドを作成する場合、非常に低いメモリの状況が発生する可能性があり、いくつかのメモリ空間を占有します。

私たちがもたらし繰り返し、スレッド作成オーバーヘッド破壊を避けるために、複合体を介したスレッド、スレッドプールの概念を導入し、メモリオーバーフローを引き起こす多数のスレッドを作成するときに避けるために、スレッドの最大数を設定することができますこの2つの問題を解決するために。

スレッドプールを使用します

スレッドプールの1コアパラメータ

私は、最初のコンストラクタのパラメータを理解する必要がありますスレッドプールのスレッドプールを習得したいです:

パラメータ名 タイプ 意味
corePoolSize int型 スレッドのコア数
maxPoolSize int型 スレッドの最大数
keepAliveTimeが 長いです 生存時間を維持
ワークキュー BlockingQueueの タスクストアキュー
threadFactory ThreadFactory 新しいスレッドを作成するスレッドプールの必要性がThreadFactoryによって作成された場合
ハンドラ RejectedExecutionHandler スレッドプールがタスクを受け入れることができないときは、ポリシーを否定取ら提出します

これらのパラメータのいずれかの解釈によって一つは、理解することは困難であり、ここで私は、処理スレッドプールを説明するためのフローチャートを組み合わせました:

画像

我々は、スレッドプールにタスクを送信すると、スレッドプール内のスレッドの数が少なくcorePoolSize以上であれば、それは直接タスクを処理する新しいスレッドを作成します。

スレッドプール内のスレッドの数がcorePoolSizeに達し、ストア・キューが満杯でない場合は、タスクがワークキューのタスクキューに格納されます。

ストアキューがいっぱいだったが、スレッドの数がまだmaxPoolSizeに達していない場合は、この時間は、それがタスクを実行するスレッドを作成していきます。注:スレッドプール内のスレッドの数。この時間は、スレッドプール内のcorePoolSizeスレッドが生きなかったであろう、と彼らは引退し、設定時間後にkeepAliveTimeが上に座ったときに、それが破壊される以上、corePoolSizeを超えました。

スレッド数が再び場合は、タスクを今回maxPoolSizeに達した場合は、ハンドラを取るためにスレッドプールは、ポリシーが指定されたタスクを拒否し否定します。

2.いくつかの一般的なスレッドプールの分析

Javaは私たちのためにいくつかの一般的なスレッドプールを提供し、あなたは簡単にエグゼキュークラスを介してそれらを得ることができます。ここでは、これらのスレッドプールの類似点と相違点を理解するために、スレッドプールで使用されるパラメータのこれらのタイプを分析します。

  1. newSingleThreadExecutor

イェ文字通り、これはその構成パラメータは次の通りであり、シングルスレッドのスレッドプールである(作成時はここでは、呼び出したスレッドプールのコンストラクタの次のレベルでの質量の参加を参照して、質量の参加を必要としません)。

corePoolSize :. 1
maximumPoolSize(maxPoolSize):. 1
keepAliveTimeが:0L
ワークキュー:LinkedBlockingQueue
他のデフォルトパラメータ

これはシングルスレッドのスレッドプールで、なぜあなたが知っている、上記輝く投入されたジョブフローシミュレーションに基づいて再度行きます。

ミッションを提出した場合、タスクを実行するためのスレッドを作成し、第2のタスクを提出するときに、タスクがジョブキューに配置されるようにcorePoolSize値は、1であるからです。タスクキューの選択がLinkedBlockingQueueあるので、基本的な構造はリストであり、理論的には、タスクのほとんど無限の数を(デフォルトのサイズにInteger.MAX_VALUEで)保存することができ、それはタスクキューがいっぱいになって、それは永遠に続かないトリガーはありませんスレッドを増やし、スレッドプールは、シングルスレッドの作業を続けることができます。

スレッドが異常終了したという理由だけならば、スレッドプールは、新しいスレッドまでに作成されます。キューを遮断することによって、スレッドプールは、タスクが順次実行されることを保証します。

  1. newFixedThreadPool

これは次のようにコンフィギュレーションパラメータは、スレッドプール内のスレッドの固定数です。

corePoolSize:N-
maximumPoolSize(maxPoolSize):N-
keepAliveTimeが:0L
ワークキュー:LinkedBlockingQueue
他のデフォルトパラメータ

あなたはSingleThreadExecutor制限がタスクを実行するための唯一のスレッドであるかを理解場合は、ここではスレッドの固定数の原理は同じで、キーは、同じサイズのcorePoolSizeとmaxPoolSizeを定義して、ほぼ無制限容量LinkedBlockingQueueを使用することです

  1. newCachedThreadPool

次のようにスレッドプールをキャッシュすることができ、私はキャッシュがスレッド上でキャッシュされていることを理解し、その構成パラメータは、次のとおりです。

corePoolSize:0
maximumPoolSize(maxPoolSize):Integer.MAX_VALUEの
keepAliveTimeが:60L
ワークキュー:SynchronousQueue
他のデフォルトパラメータ

タスクが直接、ブロッキングキューにスレッドプールに提出されますので、原因corePoolSizeした後、0です。また、ブロッキングキューSynchronousQueueを使用するので、それがキューに格納されていないタスクである、そのまま第3ブロックのフローチャートをトリガし、一旦分散タスク処理スレッドをタスクするかを決定する:電流が少ないmaxPoolSize上のスレッドの数を超える場合スレッドを作成します。maxPoolSizeが大きな値を設定しているので、あなたは基本的に作成できるスレッドのJVMの最大数の特定の番号に休憩を取って、無期限にスレッドを作成することができます。スレッドがアイドル状態の場合はタスク60秒は、スレッドプールをリサイクルすることはありません。

非同期短いリンクタスクより良い性能の多数を扱うときに、スレッドプールは、彼の空き時間に、持っているシステムリソースを節約し、何のスレッドプールではありません。

  1. newScheduledThreadPool

corePoolSize:カスタム
maximumPoolSize(maxPoolSize):Integer.MAX_VALUEの
keepAliveTimeが:0
ワークキュー:DelayedWorkQueue
他のデフォルトパラメータ

maxPoolSizeにInteger.MAX_VALUEを設定しているので、スレッドプールのスレッドがブロッキングキューがDelayedWorkQueueを選択したため、それが定期的にタスクを実行することができ、無制限に作成することができます。

  1. newWorkStealingPool

これはJDK1.8、新たに追加されたスレッドプール、ForkJoinPoolを用いたボトムです。あなたが作成されるデフォルトのパラメータを使用する場合は、スレッド・プールには、並列処理能力を一致させるために多くの達成するために、スレッドとシステムとして作成することができます。各スレッドは現在のスレッドの仕事が終わったならば、それは、完全にマルチコアCPUを利用する能力をタスクの実行を「盗む」別のジョブキューに行きます、独自のジョブキューを持っています。

スレッドプールの作成に関する規制についてアリババ

Java開発マニュアルを取り扱うアリババから次の一節は、私は上記のパラメータを読んだ後信じ、これに関するルールを理解することは困難ではない、様々なスレッドプールの類似点と相違点を説明します。

(VI)は、同時処理
4. [必須]スレッドプールエグゼキュータは、作成することはできませんが、ThreadPoolExecutorの方法により、このアプローチは、学生が資源の枯渇の危険性を回避するために、より明示的な運用ルールのスレッドプールを作成することができます。

説明:エグゼキュータは、以下のようにスレッドプールの欠点に戻る
:1)及びFixedThreadPool SingleThreadPool
それによってOOMを引き起こす、多数の要求を蓄積し得る、許容リクエストキュー長Integer.MAX_VALUEの。
2)CacheThreadPoolとScheduledThreadPoolは:
あなたは、Integer.MAX_VALUEでのスレッドの数を作成するためにOOMをその結果、多数のスレッドを作成することができます。

3.くらいが適切であるかのスレッドプールの数?

この問題に対する答えが固定されていない、我々は、スレッドプールを計算する数式の番号が与えられ、業界の権威によって起動し、さらに特定の圧力測定の数によって確認することができます。

ガイダンスは、式産業で与えられます。

  1. タスクが(等暗号化、ハッシュ計算など)CPU集約的なタスクである場合、スレッドの数はCPUコアの約1~2倍の数に設定することができます。

  2. スレッド= CPUコア*(1つの+平均待ち時間/平均処理時間):タスクは、時間のかかる(そのようなデータベースを読み書きなど、ファイル、ネットワークなど)の作業IOタイプ、スレッド数の計算式であれば

これら二つの異なるデザインは、CPUのパフォーマンスを圧迫しようとしているの原則に従ってきました。

5つの状態4.スレッドプール

5つの状態のスレッドプールThreadPoolExecutorクラスで書かれており、それらはされています。

  1. RUNNING:新しいタスクを受け入れ、新しいタスクを扱います
  2. SHUTDOWN:新しいタスクを受け入れませんが、タスクキューを処理します
  3. STOP:新しいタスクを受け入れない、タスクキューが処理されている割り込みタスクを処理しません。
  4. 片付け:すべてのタスクが終了している、workerCountゼロ、そしてスレッドは状態を片付けに行くと終了()フックメソッドを実行します
  5. TERMINATED:終了()操作が完了

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

原則を見にスレッドプールを読んで、タスクを処理する新しいスレッドを作成する方法で見てみましょうは簡単です:

//首先把我们要放在线程里运行的代码在Runnable接口实现类的run方法中封装好

class MyTask implements Runnable {

    @Override
    public void run() {
        System.out.println("处理任务 + 1");
    }
}

//然后创建一个线程,把该Runnable接口实现类作为构造参数传给线程

public class Basic {
    public static void main(String[] args) {
        Thread thread = new Thread(new MyTask());
        thread.start();
    }
}
//最后调用线程的start方法运行,实际上调用的是Runnable的run方法

インタフェースRunnableをインスタンスは、スレッドクラスに渡された上記のコード実装では、メンバ変数スレッドオブジェクト、実行メソッドは、インスタンスを呼び出したときに実行中のスレッドになりました。

タスクを実行するために、新しく作成されたスレッドを見ることができた場合は、タスクとスレッドが一緒に結合されました。スレッドプールの重要な原則は、それがブロッキングキュー、タスクとスレッドのデカップリングを追加することです

スレッドプールでは、労働者の概念があり、この概念を説明するのは少し難しい作業員がそのタスク手に、呼び出しスレッドプールrunWorker()メソッドは、スレッドの意志ワーカースレッドであるとして、あなたは、単に理解することができます詳細は以下のコードを参照するために、タスクを処理

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {//会到阻塞队列中获取任务
            w.lock();
            //...
            try {
                //执行任务
            } finally {
                //...
                w.unlock();
            }
        }
        //...
    } finally {
        //...
    }
}

あなたがスレッドプール内のコードからキーコードはwhileループで見ることができ、whileループは、タスクの実行に到達するために、ブロッキングキュータスクを取得していきます。


参考:

  1. ムークラスのネットワーク「楽しいのJava並行処理ユーティリティ、熟練しJUC、ジェネラリストによって複雑になる」講座
  2. https://www.oschina.net/question/565065_86540
  3. https://www.cnblogs.com/dolphin0520/p/3932921.html
  4. https://www.cnblogs.com/ok-wolf/p/7761755.html

おすすめ

転載: www.cnblogs.com/tanshaoshenghao/p/12626462.html