Java スレッド プールとは何ですか? Javaスレッドプールの詳しい説明

不言
リリース: 2018-09-19 15:13:35
オリジナル
2114 人が閲覧しました

この記事では、Java スレッド プールとは何ですか? Java スレッド プールの詳細な説明は、参考になると思います。

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

java.util.concurrent.Executors は、スレッドを作成するための java.util.concurrent.Executor インターフェイスの実装を提供します。プール

マルチスレッド テクノロジは、主にプロセッサ ユニットでのマルチスレッド実行の問題を解決し、プロセッサ ユニットのアイドル時間を大幅に短縮し、プロセッサ ユニットのスループット容量を向上させることができます。

サーバーがタスクを完了するのに必要な時間が、T1 スレッドの作成時間、T2 スレッド内でタスクの実行時間、T3 スレッドの破棄時間であるとします。

場合: T1 T3 が T2 よりはるかに大きい場合、スレッド プールを使用してサーバーのパフォーマンスを向上させることができます。

スレッド プールには、次の 4 つの基本コンポーネントが含まれています:

  • 1. スレッド プール マネージャー (ThreadPool): スレッド プールの作成と管理に使用されます。スレッド プールの作成、スレッド プールの破棄、新しいタスクの追加を含みます。

  • 2. ワーカー スレッド (PoolWorker): スレッド プール内のスレッドは、タスクがない場合は待機状態になります。タスクの周期的実行;

  • 3. タスク インターフェイス (タスク): ワーカー スレッドがタスクの実行をスケジュールするために実装する必要があるインターフェイス。タスクのエントリ。タスク実行後の終了作業、タスクの実行ステータスなど。

  • 4. タスクキュー (taskQueue): 未処理のタスクを格納するために使用されます。バッファリングメカニズムを提供します。

スレッド プール テクノロジは、T1 時間と T3 時間を短縮または調整する方法に焦点を当てており、それによってサーバー プログラムのパフォーマンスが向上します。サーバー プログラムが顧客のリクエストを処理するときに、T1 と T3 のオーバーヘッドが発生しないように、サーバー プログラムの起動時間帯と終了時間帯、または一部のアイドル時間帯に T1 と T3 をそれぞれ配置します。

スレッド プールは、T1 と T3 が生成される期間を調整するだけでなく、作成されるスレッドの数を大幅に削減します。

# 例を見てみましょう。 ##サーバーに 1 日あると仮定します。処理するリクエストは 50,000 件あり、各リクエストを完了するには別のスレッドが必要です。スレッド プールでは通常、スレッドの数は固定されているため、サーバーがこれらのリクエストの処理にスレッド プールを使用しない場合、生成されるスレッドの総数はスレッド プール内のスレッドの数を超えることはありません。スレッド数は 50,000 になります。一般的なスレッド プール サイズは 50,000 よりもはるかに小さいです。したがって、スレッド プールを使用するサーバー プログラムは、50,000 個を作成するためにリクエストの処理に時間を費やすことがなくなり、効率が向上します。

2. 共通スレッド プール

①newSingleThreadExecutor

シングル スレッド スレッド プール。つまり、スレッド プール内で一度に 1 つのスレッドだけが動作します。 、および単一のスレッド文字列 行内のタスクを実行します。

②newFixedThreadExecutor(n)

タスクが送信されない場合、スレッド プールの固定数は 1 つになります。スレッド プールの最大数に達するまでスレッドを実行し、後で入力します。前のタスクが完了するまでキューが実行を継続するのを待ちます。

③newCacheThreadExecutor (推奨)

キャッシュ可能なスレッド プール、

スレッド プールのサイズが処理タスクを超える場合、必要なスレッドが必要な場合、一部のアイドル状態 (通常は 60 秒間実行されない) スレッド がリサイクルされ、タスクが到着すると、新しいスレッドが再利用されます。実行のためにインテリジェントに追加されます。

④newScheduleThreadExecutor

無制限のスレッド プール サイズ、スケジュールされた定期的な実行スレッドをサポート

Java によって提供されるスレッド プールはより強力です。スレッド プールの動作原理を理解していれば、クラス ライブラリでスレッド プールを見ても違和感はなくなると思います。

Java スレッド プールとは何ですか? Javaスレッドプールの詳しい説明

Java スレッド プールとは何ですか? Javaスレッドプールの詳しい説明

記事 2:

Java スレッド プールの使用手順

1 はじめに

jdk1.4 およびそれ以前の jdk バージョンでは、スレッドの使用が非常に重要な位置を占めています。プールの使い方は非常に雑です。この状況は jdk1.5 以降大きく変わりました。 Jdk1.5 以降、java.util.concurrent パッケージが追加されました。このパッケージは主に Java でのスレッドとスレッド プールの使用を紹介します。これは、開発中のスレッドの問題に対処するのに非常に役立ちます。

2: スレッド プール

スレッド プールの役割:

スレッド プールの機能は、システム内の実行スレッドの数を制限することです。
システム環境に応じて、スレッドの数を自動または手動で設定して最適な運用効果を実現できます。スレッドの数が少ないとシステム リソースの無駄が発生し、多いとシステムの輻輳や非効率が発生します。スレッド プールを使用してスレッドの数を制御すると、他のスレッドはキューに入れられて待機します。タスクが実行されると、キュー内の最前部のタスクが取得され、実行が開始されます。キュー内に待機中のプロセスがない場合、スレッド プールのこのリソースは待機中になります。新しいタスクを実行する必要がある場合、スレッド プールに待機中のワーカー スレッドがあれば実行を開始できます。それ以外の場合は、待機キューに入ります。

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

1. スレッドの作成と破棄の数を減らし、各ワーカー スレッドを再利用して複数のタスクを実行できます。

2. システムの容量に応じてスレッド プール内の作業スレッドの数を調整して、過剰なメモリ消費によるサーバーの枯渇を防ぐことができます (各スレッドには約 1 MB のメモリが必要で、スレッドが開始されます)。メモリの消費量が増えると、より多くのメモリが消費され、最終的にはシステムがクラッシュします)。

Java におけるスレッド プールの最上位インターフェイスは Executor ですが、厳密に言えば、Executor はスレッド プールではなく、スレッドを実行するための単なるツールです。実際のスレッド プール インターフェイスは ExecutorService です。

いくつかの重要なカテゴリ:

リアル スレッド プール インターフェイス。 は Timer/TimerTask に似ており、タスクの繰り返し実行が必要な問題を解決できます。 ExecutorService のデフォルトの実装。 ThreadPoolExecutor の ScheduledExecutorService インターフェイス実装 (定期的なタスク スケジューリングのクラス実装) を継承します。

スレッド プールの構成は比較的複雑です。特にスレッド プールの原理があまり明確でない場合、構成されたスレッド プールが最適ではない可能性が非常に高いため、いくつかの静的ファクトリが Executors クラスで提供されます。よく使用されるスレッド プールをいくつか生成します。

1. newSingleThreadExecutor

シングルスレッド スレッド プールを作成します。このスレッド プールには 1 つのスレッドだけが動作しており、これはすべてのタスクを直列に実行する単一のスレッドと同等です。唯一のスレッドが異常終了した場合、新しいスレッドがそれを置き換えます。このスレッド プールにより、すべてのタスクが送信された順序で実行されることが保証されます。

2.newFixedThreadPool

固定サイズのスレッド プールを作成します。スレッドは、スレッド プールの最大サイズに達するまで、タスクが送信されるたびに作成されます。スレッド プールのサイズは、最大値に達しても変更されません。実行例外によってスレッドが終了すると、スレッド プールは新しいスレッドで補充されます。

3. newCachedThreadPool

キャッシュ可能なスレッド プールを作成します。スレッド プールのサイズがタスクの処理に必要なスレッドを超える場合、

その後、いくつかのアイドル スレッド (60 秒間タスクが実行されていない) がリサイクルされます。タスクの数が増加した場合、このスレッド プールを追加できます。インテリジェントにタスクを処理するための新しいスレッド。このスレッド プールは、スレッド プールのサイズを制限しません。スレッド プールのサイズは、オペレーティング システム (または JVM) が作成できる最大スレッド サイズに完全に依存します。

4.newScheduledThreadPool

サイズ無制限のスレッド プールを作成します。このスレッド プールは、タスクのタイミングと定期的な実行をサポートします。

インスタンス

##1: newSingleThreadExecutor

package com.thread;
 /* * 
  *通过实现Runnable接口,实现多线程
 * Runnable类是有run()方法的;
 * 但是没有start方法
 * 参考:
 * http://blog.csdn.net/qq_31753145/article/details/50899119 * */

public class MyThread extends Thread { 

    @Override public void run() { // TODO Auto-generated method stub // super.run();
    System.out.println(Thread.currentThread().getName()+"正在执行....");
    } 
}
ログイン後にコピー
package com.thread; 
import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; 
/* 
 * 通过实现Runnable接口,实现多线程
 * Runnable类是有run()方法的;
 * 但是没有start方法
 * 参考:
 * http://blog.csdn.net/qq_31753145/article/details/50899119 * */

public class singleThreadExecutorTest{ public static void main(String[] args) { // TODO Auto-generated method stub //创建一个可重用固定线程数的线程池
        ExecutorService pool=Executors.newSingleThreadExecutor(); //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
 Thread t1=new MyThread();

        Thread t2=new MyThread();

        Thread t3=new MyThread();

        Thread t4=new MyThread();

        Thread t5=new MyThread(); //将线程放到池中执行;
 pool.execute(t1);

        pool.execute(t2);

        pool.execute(t3);

        pool.execute(t4);

        pool.execute(t5); //关闭线程池
 pool.shutdown();

    }

}
ログイン後にコピー
結果:

pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
ログイン後にコピー

2newFixedThreadPool

 package com.thread; 
import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors; 
/* * 通过实现Runnable接口,实现多线程
 * Runnable类是有run()方法的;
 * 但是没有start方法
 * 参考:
 * http://blog.csdn.net/qq_31753145/article/details/50899119 * */

public class fixedThreadExecutorTest{ public static void main(String[] args) { // TODO Auto-generated method stub //创建一个可重用固定线程数的线程池
        ExecutorService pool=Executors.newFixedThreadPool(2); //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
 Thread t1=new MyThread();

        Thread t2=new MyThread();

        Thread t3=new MyThread();

        Thread t4=new MyThread();

        Thread t5=new MyThread(); //将线程放到池中执行;
 pool.execute(t1);

        pool.execute(t2);

        pool.execute(t3);

        pool.execute(t4);

        pool.execute(t5); //关闭线程池
 pool.shutdown();

    }

}
ログイン後にコピー
結果:

pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-1正在执行....
pool-1-thread-2正在执行....
ログイン後にコピー
3,

newCachedThreadPool

package com.thread;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
 /* 
 * 通过实现Runnable接口,实现多线程
 * Runnable类是有run()方法的;
 * 但是没有start方法
 * 参考:
 * http://blog.csdn.net/qq_31753145/article/details/50899119 * */

public class cachedThreadExecutorTest{ public static void main(String[] args) { // TODO Auto-generated method stub //创建一个可重用固定线程数的线程池
        ExecutorService pool=Executors.newCachedThreadPool(); //创建实现了Runnable接口对象,Thread对象当然也实现了Runnable接口;
 Thread t1=new MyThread();

        Thread t2=new MyThread();

        Thread t3=new MyThread();

        Thread t4=new MyThread();

        Thread t5=new MyThread(); //将线程放到池中执行;
 pool.execute(t1);

        pool.execute(t2);

        pool.execute(t3);

        pool.execute(t4);

        pool.execute(t5); //关闭线程池
 pool.shutdown();

    }

}
ログイン後にコピー
結果:

pool-1-thread-2正在执行....
pool-1-thread-1正在执行....
pool-1-thread-3正在执行....
pool-1-thread-4正在执行....
pool-1-thread-5正在执行....
ログイン後にコピー
4,

newScheduledThreadPool

package com.thread; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; 
/* * 通过实现Runnable接口,实现多线程
 * Runnable类是有run()方法的;
 * 但是没有start方法
 * 参考:
 * http://blog.csdn.net/qq_31753145/article/details/50899119 * */

public class scheduledThreadExecutorTest{ public static void main(String[] args) { // TODO Auto-generated method stub
 ScheduledThreadPoolExecutor exec =new ScheduledThreadPoolExecutor(1);
       exec.scheduleAtFixedRate(new Runnable(){//每隔一段时间就触发异常
 @Override public void run() { // TODO Auto-generated method stub //throw new RuntimeException();
            System.out.println("===================");

        }}, 1000, 5000, TimeUnit.MILLISECONDS);  

       exec.scheduleAtFixedRate(new Runnable(){//每隔一段时间打印系统时间,证明两者是互不影响的
 @Override public void run() { // TODO Auto-generated method stub
 System.out.println(System.nanoTime());

        }}, 1000, 2000, TimeUnit.MILLISECONDS);

    }

}
ログイン後にコピー
結果:

===================
23119318857491
23121319071841
23123319007891
===================
23125318176937
23127318190359
===================
23129318176148
23131318344312
23133318465896
===================
23135319645812
ログイン後にコピー
3: ThreadPoolExecutor の詳細説明

ThreadPoolExecutor の完全な構築メソッドの署名は次のとおりです:

ThreadPoolExecutor( int corePoolSize、int minimumPoolSize、long keepAliveTime、TimeUnit ユニット、BlockingQueue workQueue、ThreadFactory threadFactory、RejectedExecutionHandler handler) .

corePoolSize - プールに保存されているスレッドの数アイドル状態のスレッドを含む。

maximumPoolSize - プール内で許可されるスレッドの最大数。

keepAliveTime - スレッドの数がコアよりも大きい場合、これは、過剰なアイドル スレッドが終了するまでに新しいタスクを待機する最大時間です。

unit - keepAliveTime パラメーターの時間単位。

workQueue - 実行前にタスクを保持するために使用されるキュー。このキューは、execute メソッドによって送信された実行可能なタスクのみを保持します。

threadFactory - 新しいスレッドを作成するためにエグゼキュータによって使用されるファクトリ。

handler - スレッド スコープとキュー容量を超えたために実行がブロックされた場合に使用されるハンドラー。

ThreadPoolExecutor は、Executors クラスの基礎となる実装です。

JDK ヘルプ ドキュメントには、次のような一節があります。

「プログラマは、より便利な

Executorsfactory メソッド を使用することを強くお勧めします。」 Executors.newCachedThreadPool () (無制限のスレッド プール、自動スレッド リサイクルが実行可能)、Executors.newFixedThreadPool(int) (固定サイズのスレッド プール) Executors.newSingleThreadExecutor() (単一のバックグラウンド スレッド)

これらはすべて、ほとんどの使用シナリオに合わせて事前定義された設定を持っています。」

いくつかのクラスのソース コードを以下に紹介します:

ExecutorService newFixedThreadPool ( int nThreads) :固定サイズのスレッド プール。

corePoolSize と minimumPoolSize のサイズが同じであること (実際には、後で紹介しますが、無制限のキューを使用する場合、maximumPoolSize パラメータは意味がありません) と、設定テーブル名が同じであることがわかります。 keepAliveTime と単位 何か? -生きていたくないと気づく時が来ました!最後の BlockingQueue は、無制限であるという特徴を持つ LinkedBlockingQueue を選択しました。

public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<runnable>());   

      }</runnable>
ログイン後にコピー

ExecutorService newSingleThreadExecutor(): 単一スレッド

public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService   
                 (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<runnable>()));   
       }</runnable>
ログイン後にコピー

ExecutorService newCachedThreadPool(): 無制限のスレッド プール、自動スレッド リサイクルを実行できます

この実装は興味深いです。 1 つ目は無制限のスレッド プールであるため、maximumPoolSize が非常に大きいことがわかります。次に、BlockingQueue の選択には SynchronousQueue が使用されます。この BlockingQueue については少し馴染みがないかもしれません。簡単に言えば、この QUEUE では、各挿入操作は別のスレッドの対応する削除操作を待つ必要があります。

 public static ExecutorService newCachedThreadPool() {
   return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<runnable>());   
    }</runnable>
ログイン後にコピー
パラメーター BlockingQueue から始めましょう。 JDK では、実際には 3 種類のキューがあることが明確にされています。

すべての BlockingQueue は、送信されたタスクの転送と保持に使用できます。このキューは、プール サイズを操作するために使用できます:

如果运行的线程少于 corePoolSize,则 Executor始终首选添加新的线程,而不进行排队。(如果当前运行的线程小于corePoolSize,则任务根本不会存放,添加到queue中,而是直接抄家伙(thread)开始运行)

如果运行的线程等于或多于 corePoolSize,则 Executor始终首选将请求加入队列,而不添加新的线程

如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。

queue上的三种类型。

排队有三种通用策略:

直接提交。工作队列的默认选项是 SynchronousQueue,它将任务直接提交给线程而不保持它们。在此,如果不存在可用于立即运行任务的线程,则试图把任务加入队列将失败,因此会构造一个新的线程。此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。直接提交通常要求无界 maximumPoolSizes 以避免拒绝新提交的任务。当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

无界队列。使用无界队列(例如,不具有预定义容量的 LinkedBlockingQueue)将导致在所有corePoolSize 线程都忙时新任务在队列中等待。这样,创建的线程就不会超过 corePoolSize。(因此,maximumPoolSize的值也就无效了。)当每个任务完全独立于其他任务,即任务执行互不影响时,适合于使用无界队列;例如,在 Web页服务器中。这种排队可用于处理瞬态突发请求,当命令以超过队列所能处理的平均数连续到达时,此策略允许无界线程具有增长的可能性。

有界队列。当使用有限的 maximumPoolSizes时,有界队列(如 ArrayBlockingQueue)有助于防止资源耗尽,但是可能较难调整和控制。队列大小和最大池大小可能需要相互折衷:使用大型队列和小型池可以最大限度地降低 CPU 使用率、操作系统资源和上下文切换开销,但是可能导致人工降低吞吐量。如果任务频繁阻塞(例如,如果它们是 I/O边界),则系统可能为超过您许可的更多线程安排时间。使用小型队列通常要求较大的池大小,CPU使用率较高,但是可能遇到不可接受的调度开销,这样也会降低吞吐量。  

BlockingQueue的选择。

例子一:使用直接提交策略,也即SynchronousQueue。

首先SynchronousQueue是无界的,也就是说他存数任务的能力是没有限制的,但是由于该Queue本身的特性,在某次添加元素后必须等待其他线程取走后才能继续添加。在这里不是核心线程便是新创建的线程,但是我们试想一样下,下面的场景。

我们使用一下参数构造ThreadPoolExecutor:

 new ThreadPoolExecutor( 2, 3, 30, TimeUnit.SECONDS, new  SynchronousQueue<runnable>(), new RecorderThreadFactory("CookieRecorderPool"), new ThreadPoolExecutor.CallerRunsPolicy());</runnable>
ログイン後にコピー

当核心线程已经有2个正在运行.

  1. 此时继续来了一个任务(A),根据前面介绍的“如果运行的线程等于或多于 corePoolSize,则Executor始终首选将请求加入队列,而不添加新的线程。”,所以A被添加到queue中。

  2. 又来了一个任务(B),且核心2个线程还没有忙完,OK,接下来首先尝试1中描述,但是由于使用的SynchronousQueue,所以一定无法加入进去。

  3. 此时便满足了上面提到的“如果无法将请求加入队列,则创建新的线程,除非创建此线程超出maximumPoolSize,在这种情况下,任务将被拒绝。”,所以必然会新建一个线程来运行这个任务。

  4. 暂时还可以,但是如果这三个任务都还没完成,连续来了两个任务,第一个添加入queue中,后一个呢?queue中无法插入,而线程数达到了maximumPoolSize,所以只好执行异常策略了。

所以在使用SynchronousQueue通常要求maximumPoolSize是无界的,这样就可以避免上述情况发生(如果希望限制就直接使用有界队列)。对于使用SynchronousQueue的作用jdk中写的很清楚:此策略可以避免在处理可能具有内部依赖性的请求集时出现锁。

什么意思?如果你的任务A1,A2有内部关联,A1需要先运行,那么先提交A1,再提交A2,当使用SynchronousQueue我们可以保证,A1必定先被执行,在A1么有被执行前,A2不可能添加入queue中。

例子二:使用无界队列策略,即LinkedBlockingQueue

这个就拿newFixedThreadPool来说,根据前文提到的规则:

如果运行的线程少于 corePoolSize,则 Executor 始终首选添加新的线程,而不进行排队。那么当任务继续增加,会发生什么呢?

如果运行的线程等于或多于 corePoolSize,则 Executor 始终首选将请求加入队列,而不添加新的线程。OK,此时任务变加入队列之中了,那什么时候才会添加新线程呢?

如果无法将请求加入队列,则创建新的线程,除非创建此线程超出 maximumPoolSize,在这种情况下,任务将被拒绝。这里就很有意思了,可能会出现无法加入队列吗?不像SynchronousQueue那样有其自身的特点,对于无界队列来说,总是可以加入的(资源耗尽,当然另当别论)。换句说,永远也不会触发产生新的线程!corePoolSize大小的线程数会一直运行,忙完当前的,就从队列中拿任务开始运行。所以要防止任务疯长,比如任务运行的实行比较长,而添加任务的速度远远超过处理任务的时间,而且还不断增加,不一会儿就爆了。

例子三:有界队列,使用ArrayBlockingQueue。

这个是最为复杂的使用,所以JDK不推荐使用也有些道理。与上面的相比,最大的特点便是可以防止资源耗尽的情况发生。

举例来说,请看如下构造方法:

 new ThreadPoolExecutor( 2, 4, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<runnable>(2), new RecorderThreadFactory("CookieRecorderPool"), new ThreadPoolExecutor.CallerRunsPolicy());</runnable>
ログイン後にコピー

假设,所有的任务都永远无法执行完。

对于首先来的A,B来说直接运行,接下来,如果来了C,D,他们会被放到queue中,如果接下来再来E,F,则增加线程运行E,F。但是如果再来任务,队列无法再接受了,线程数也到达最大的限制了,所以就会使用拒绝策略来处理。

keepAliveTime

jdk中的解释是:当线程数大于核心时,此为终止前多余的空闲线程等待新任务的最长时间。

有点拗口,其实这个不难理解,在使用了“池”的应用中,大多都有类似的参数需要配置。比如数据库连接池,DBCP中的maxIdle,minIdle参数。

什么意思?接着上面的解释,后来向老板派来的工人始终是“借来的”,俗话说“有借就有还”,但这里的问题就是什么时候还了,如果借来的工人刚完成一个任务就还回去,后来发现任务还有,那岂不是又要去借?这一来一往,老板肯定头也大死了。

合理的策略:既然借了,那就多借一会儿。直到“某一段”时间后,发现再也用不到这些工人时,便可以还回去了。这里的某一段时间便是keepAliveTime的含义,TimeUnit为keepAliveTime值的度量。

RejectedExecutionHandler

另一种情况便是,即使向老板借了工人,但是任务还是继续过来,还是忙不过来,这时整个队伍只好拒绝接受了。

RejectedExecutionHandler接口提供了对于拒绝任务的处理的自定方法的机会。在ThreadPoolExecutor中已经默认包含了4中策略,因为源码非常简单,这里直接贴出来。

CallerRunsPolicy:线程调用运行该任务的 execute 本身。此策略提供简单的反馈控制机制,能够减缓新任务的提交速度。

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) {

               r.run();

           }

       }
ログイン後にコピー

这个策略显然不想放弃执行任务。但是由于池中已经没有任何资源了,那么就直接使用调用该execute的线程本身来执行。

AbortPolicy:处理程序遭到拒绝将抛出运行时RejectedExecutionException

 这种策略直接抛出异常,丢弃任务。

DiscardPolicy:不能执行的任务将被删除

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {

       }
ログイン後にコピー

 这种策略和AbortPolicy几乎一样,也是丢弃任务,只不过他不抛出异常。

DiscardOldestPolicy:如果执行程序尚未关闭,则位于工作队列头部的任务将被删除,然后重试执行程序(如果再次失败,则重复此过程)

public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { 
if (!e.isShutdown()) {

               e.getQueue().poll();

               e.execute(r);

           }

       }
ログイン後にコピー

该策略就稍微复杂一些,在pool没有关闭的前提下首先丢掉缓存在队列中的最早的任务,然后重新尝试运行该任务。这个策略需要适当小心。

设想:如果其他线程都还在运行,那么新来任务踢掉旧任务,缓存在queue中,再来一个任务又会踢掉queue中最老任务。

总结:

keepAliveTime和maximumPoolSize及BlockingQueue的类型均有关系。如果BlockingQueue是无界的,那么永远不会触发maximumPoolSize,自然keepAliveTime也就没有了意义。

反之,如果核心数较小,有界BlockingQueue数值又较小,同时keepAliveTime又设的很小,如果任务频繁,那么系统就会频繁的申请回收线程。

public static ExecutorService newFixedThreadPool(int nThreads) {
 return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<runnable>());
}</runnable>
ログイン後にコピー

分類 関数
##ExecutorService
ScheduledExecutorService
ThreadPoolExecutor
ScheduledThreadPoolExecutor

以上がJava スレッド プールとは何ですか? Javaスレッドプールの詳しい説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

関連ラベル:
ソース:php.cn
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート