=====記事ディレクトリ=====
問題
スレッドプールの長所と短所はどこにありますか?
スレッドプールの基本的な実装原則は何ですか?
日常の開発でスレッドプールをうまく活用するにはどうすればよいですか?
スレッドプールで実際に使用されているのはどれですか?
スレッドプールThreadPoolExecutor
コンセプト
スレッドプールによって行われる作業は、主に実行中のスレッドの数を制御することです。処理中にタスクがキューに追加され、スレッドが作成された後にこれらのタスクが開始されます。最大数を超えると、超過したスレッドは順番に待機し、他のスレッドを待機します。実行が完了すると、タスクは実行のためにキューから削除されます。
利点
彼の主な機能は、スレッドの再利用、同時実行の最大数の制御、およびスレッドの管理です。
- スレッドの再利用:新しいスレッドを保持したり、作成されたスレッドを再利用してスレッドの作成と破棄のオーバーヘッドを削減したり、システムリソースを節約したりする必要はありません。
- 応答速度の向上:タスクに到達したら、新しいスレッドを作成する必要はなく、スレッドプールのスレッドを直接使用します。
- 管理スレッド:同時実行の最大数を制御したり、スレッドの作成を制御したりできます。
システム
Executor
→ ExecutorService
→ AbstractExecutorService
→ ThreadPoolExecutor
。ThreadPoolExecutor
これは、スレッドプールによって作成されたコアクラスです。ツールと同様Arrays
に、独自のツールもあります。Collections
Executor
Executors
アーキテクチャの実装
Javaのスレッドプールは、Executor、Executors、ExecutorService、およびThreadPoolExecutorクラスを使用するExecutorフレームワークを介して実装されます。
スレッドプールの使用方法
スレッドプールを作成する3つの一般的な方法
newFixedThreadPool:LinkedBlockingQueue
実装、固定長スレッドプールを使用します。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
newSingleThreadExecutor:LinkedBlockingQueue
実装を使用します。プールにはスレッドが1つしかありません。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
newCachedThreadPool:SynchronousQueue
実装、可変長スレッドプールを使用します。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
スレッドプールの7つのパラメータ
int corePoolSize,核心线程
int maximumPoolSize,非核心线程
long keepAliveTime,时间
TimeUnit unit,时间单位
BlockingQueue<Runnable> workQueue,队列
ThreadFactory threadFactory,线程工厂
RejectedExecutionHandler handler 拒绝策略
形
パラメータ | 意義 |
---|---|
corePoolSize | スレッドプール内の常駐コアスレッドの数 |
maximumPoolSize | 収容できるスレッドの最大数 |
keepAliveTime | アイドルスレッドの生存時間 |
単位 | 生存時間単位 |
workQueue | 送信されたが実行されなかったタスクを格納するキュー |
threadFactory | スレッドを作成するためのファクトリクラス |
ハンドラ | 待機キューがいっぱいになった後の拒否ポリシー |
メソッドノート
corePoolSize –アイドル状態であっても、プールに保持するスレッドの数。allowCoreThreadTimeOutが設定されていない限り
、
maximumPoolSize –プールに許可するスレッドの最大数keepAliveTime –スレッドの数がコアよりも多い場合、これは過剰なアイドルスレッドが終了する前に新しいタスクを待機する最大時間。
unit –keepAliveTime引数の時間単位workQueue–
タスクが実行される前にタスクを保持するために使用するキュー。このキューは、executeメソッドによって送信された実行可能タスクのみを保持します。
threadFactory –エグゼキュータが新しいスレッド
ハンドラを作成するときに使用するファクトリ–スレッドの境界とキューの容量に達したために実行がブロックされたときに使用するハンドラ
コード
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
理解:スレッドプールの作成パラメータは銀行のようなものです。
corePoolSize
たとえば、銀行の「オンデューティウィンドウ」と同じように、今日、顧客の要求(タスク)を処理する2人の窓口があります。3人以上の顧客がいる場合、新しい顧客は待機エリア(待機キュー)で待機します。ときに待合室がいっぱいです、「残業ウィンドウは」この時点でオープンする必要があり、作業残業に他の3つの出納係を許可する。このとき、最大ウィンドウは5です。すべてのウィンドウが開いていて、待機領域がまだいっぱいの場合は、この時点で「拒否戦略」をアクティブにして、入らないように顧客の流入を通知する必要があります。新規顧客の流入がなくなったため、仕事を終えた顧客が増え、ウィンドウがアイドル状態になり始めました。このとき、余分な3つの「残業ウィンドウ」をキャンセルして、2つの「デューティウィンドウ」に戻します。workQueue
maximumPoolSize
handler
keepAlivetTime
処理する
実行中のスレッドの数がcorePoolSize未満の場合は、コアスレッドを作成し、corePoolSize以上の場合は、待機キューに入れます。
待機キューがいっぱいで、実行中のスレッドの数がmaximumPoolSize未満の場合は、非コアスレッドを作成します。maximumPoolSize以上の場合は、拒否戦略を開始します。
スレッドがkeepAliveTimeの期間何の関係もない場合、実行中のスレッドの数がcorePoolSizeより大きい場合、非コアスレッドは閉じられます。
スレッドプール拒否戦略
待機キューがいっぱいになり、スレッドの最大数に達して新しいタスクが到着したら、拒否戦略を開始する必要があります。JDKは、それぞれ4つの拒否戦略を提供します。
- AbortPolicy:
RejectedExecutionException
システムが正常に実行されないように例外を直接スローするデフォルトのポリシー。 - CallerRunsPolicy:例外をスローしたり、タスクを終了したりすることはありませんが、タスクを呼び出し元に返します。
- DiscardOldestPolicy:キュー内で最も長く待機しているタスクを破棄してから、現在のタスクをキューに追加して、タスクの送信を再試行します。
- DiscardPolicy:処理せずにタスクを直接破棄します。
実際の生産で使用されるスレッドプールはどれですか(強調)?
Alijava開発マニュアルのSongshanバージョンからの画像
単一、可変、および固定長は必要ありません!理由は、FixedThreadPool
そしてSingleThreadExecutor
底部層が使用されLinkedBlockingQueue
、最大キュー長が達成されInteger.MAX_VALUE
、明らかにOOMをもたらします。したがって、実際の本番環境では、通常ThreadPoolExecutor
7つのパラメーターを渡し、スレッドプールをカスタマイズします。
ExecutorService threadPool=new ThreadPoolExecutor(2,5,
1L,TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
カスタムスレッドプールパラメータの選択
CPUを集中的に使用するタスク
CPUを集中的に使用するタスクの場合、スレッドの最大数はCPUスレッドの数+1です。
CPUを集中的に使用するということは、タスクがブロックせずに多くの計算を必要とすることを意味します。CPUはフルスピードで実行されています
。CPUを集中的に使用するタスクは、真のマルチコア
CPU (マルチスレッドによる)とシングルコアCPU(悲劇? )、シミュレートされたマルチスレッドの数に関係なく、CPUの合計計算能力はそれだけであるため、タスクを加速することはできません。
CPUを集中的に使用するタスクは、可能な限り少ないスレッドを構成します。
一般式:CPUコアの数+1スレッドプール
IOを多用するタスク
IOを多用するタスクの場合は、できるだけ多くのポイントを割り当てます。これは、CPUスレッドの数* 2、またはCPUスレッドの数/(1-ブロッキング係数)になります。
大手工場の経験
IOを多用します。つまり、タスクには多くのO、つまり多くのブロッキングが必要です。
シングルスレッドで10を多用するタスクを実行すると、待機中に多くのCPUコンピューティングパワーが無駄になります。
したがって、IOを多用するタスクでマルチスレッドを使用すると、プログラムの実行を大幅に高速化できます。シングルコアCPUでも、この加速は主に無駄なブロッキング時間を利用します。
IOが集中すると、ほとんどのスレッドがブロックされるため、スレッド数を構成する必要があります。
参照式:CPUコア数/ 1-ブロッキング係数。
ブロッキング係数は
0.8〜09です。たとえば、8コアCPU:8 /(1-0.9)=80スレッド
スレッドプールの基本的な動作原理について話します(強調)
次のコンテンツは非常に重要です、次のコンテンツは非常に重要です、次のコンテンツは非常に重要です
1.スレッドプールを作成した後、送信されたタスク要求を待ちます。
2. execute(メソッドを呼び出して要求タスクを追加すると、スレッドプールは次の判断を下します
。2.1実行中のスレッドの数がcorePoolSize未満の場合は、すぐにタスクを実行するスレッドを作成します。2.2実行中のスレッドの数がcorePoolSize以上の
場合。このタスクをキューに入れます
2.3この時点でキューがいっぱいで、実行中のスレッドの数がmaximumPoolSize未満の場合でも、このタスクをすぐに実行するには非コアスレッドを作成する必要があります
2.4キューがいっぱいで、実行中のスレッドの数がmaximumPoolSize以上の場合、次に、スレッドプールは飽和拒否戦略を開始して実行します。3
。
スレッドがタスクを完了すると、キューから次のタスクを実行のために取得します。4 。スレッドが特定の時間(keepAlive Time)を超えて何もしない場合その時点で、スレッドプールは判断します。
現在実行中のスレッドの数がcorePoolSizeより大きい場合、このスレッドは停止します。
したがって、スレッドプールのすべてのタスクが完了すると、最終的にcorePoolsizeのサイズに縮小されます。
CPUコア数の確認方法
マウスの右ボタン、いいえ!!!
System.out.println(Runtime.getRuntime().availableProcessors());
参照
Javaコンカレントプログラミング-スレッドプールThreadPoolExecutorは、
Aliボスを使用して、スレッドプール
JVM-JUC-Core Alijava開発マニュアルSongshanversion.pdfの基本原理を理解します
。