Javaスレッドプール
スレッドプールの役割
1.再利用既存のスレッド、複数の要求を処理するときに、スレッドの作成を減らし、経費の破壊が生じました。
リクエストが労働者に到達したとき2.通常、すでにシステムの応答性を向上させ、要求を待たずに、存在します。
執行staticファクトリメソッドのスレッドプール
1.newFixedThreadPool
あなたはそれがプールの最大長さに達するまで、スレッドを作成するためにタスクを送信するたびに、固定サイズのスレッドプールを作成し、スレッドプールの長さは何の変化残っていないだろう。
2.newCachedThreadPool
現在のスレッド・プールの長さはそれで需要が増加し、新しいスレッドを追加するための柔軟性かもしれアイドルスレッドを回復するための柔軟性を対処する必要性を超えた場合、キャッシュされたスレッドプールを作成します。
3.newSingleThreadExecutor
シングルスレッドexecutorを作成し、それが唯一のタスクを実行するための独自のワーカースレッドを作成し、エグゼキュータはタスクキュー(FIFO、LIFO、優先順位)の実行に基づいて指定された一連のタスクことを保証します。
4.newScheduledThreadPool
固定サイズのスレッドプールを作成するだけでなく、タイマーに似たタスクの実行のタイミングや周期性をサポートしています。
ThreadPoolExecutorスレッドプールのクラスのコンストラクタ
/ ** *指定された初期化パラメータ(ThreadPoolExecutor)によってスレッドプールを作成 * * @paramの、フリー場合は、スレッドプールcorePoolSizeコアスレッド内のスレッドのコアの数が偶数破壊されないであろう
allowCoreThreadTimeOutが設定されていない限り* * @param maximumPoolSizeスレッドプールを許容されるスレッドの最大数 * @param keepAliveTimeがアイドル状態のスレッドが破棄される前に、現在時刻が、スレッドのコアのスレッドの数よりも大きい場合を示し
*新しいタスクの到着を待機する最大時間を * @paramの単位時間単位のkeepAliveTimeがパラメータ * @param ワークキュータスクが実行されます前者はキューを格納するために使用され、キューは唯一の実行方法により提出したRunnableタスク格納します * @param threadFactoryエグゼキュータが使用される新しいスレッドファクトリを作成する * @paramのブロックされたときに起因するスレッドの数にハンドラをし、キューがいっぱいになると、政策を実行することを拒否 * @throwsIllegalArgumentException次のいずれかが成立する場合:<BR> * { @code corePoolSize <0} <BR> * { @code keepAliveTimeが<0} <BR> * { @code maximumPoolSize <= 0} <BR> * { @code maximumPoolSizeを<corePoolSize} *が@throws {場合NullPointerExceptionが@code ワークキュー} *または{ @code threadFactory}または{ @codeのハンドラ}がヌルである * / パブリック(ThreadPoolExecutor INT corePoolSize、 INTmaximumPoolSize、 長いkeepAliveTimeが、 TimeUnitでユニット、 BlockingQueueの <Runnableを> ワークキュー、 ThreadFactory threadFactory、 のRejectedExecutionHandlerハンドラ){ 場合(corePoolSize <0 || maximumPoolSize <= 0 || maximumPoolSize <corePoolSize || keepAliveTimeが <0 ) スロー 新しいはIllegalArgumentException()。 もし(ワークキュー== nullの || threadFactory == nullを|| ハンドラ== nullの) スロー 新しい(NullPointerExceptionが)。 この .ACC = System.getSecurityManager()== nullの? ヌル: AccessController.getContext(); この .corePoolSize = corePoolSize。 この .maximumPoolSize = maximumPoolSize。 この .workQueue = ワークキュー; この .keepAliveTime = unit.toNanos(keepAliveTimeが)。 この .threadFactory = threadFactory。 この .handler = ハンドラ。 }
スレッドプールのパラメータ
1.コアスレッド:アイドルが破壊されることはありませんでも、スレッドの数
2.スレッドの最大数:プールスレッドで許可されるスレッドの最大数を
3.生存時間を維持:アイドルスレッドが新しいタスクを待っている時間が破壊される前に、
4.生存時間単位:レイテンシユニット
5.ワークキュー:キューに格納されるタスク
6.ねじ工場:工場は新しいスレッドを作成
7.拒否した戦略:キューがいっぱいになったとき、スレッドの数を取り、政策を否定
作業キュー
そこに多くのジョブキューがありますが、BlockQueueインタフェースを達成しています
キュー・タイプ | スレッドプールの種類 | 機能 |
LinkedBlockingQueue | FixedThreadPool SingleThreadPool ジョブキューを使用します |
FIFOキューリストに基づいて、 |
SynchronousQueue | 作業キューを使用CachedThreadPool | ジョブ投入を保存しますが、直接、新しいタスクを実行するスレッドを作成しません |
DelayedWorkQueue | 作業キューを使用ScheduledThreadPool |
拒否ポリシー
1.AbortPolicy:タスクを破棄してRejectedExecutionException例外をスローします。
2.CallerRunsPolicy:限り、スレッドプールが閉じていないと、呼び出し側のスレッドで直接ポリシーは、現在のタスクが破棄されて実行されます。
3.DiscardOldestPolicy:タスクが実行されようとしている、タスクをキュー内で最も古い破棄し、再度現在のジョブをサブミットしてみてください。
4.DiscardPolicy:任意の処理をせずに、タスクを捨てます。
タスク処理スレッドプールポリシー
タスクは、スレッドプールを処理示されるように。
ロジックより明確に、実際には、これは論理的なスレッドプールで実行()メソッドは、ソースコードで次のルック。
//通过execute向线程池提交任务
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get();
//如果当前线程数未达到核心线程数,则直接创建线程来执行新任务 if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); }
//否则将任务加入阻塞队列,这里进行双重检查,如果线程池已经关闭,则调用reject(),
//如果当前线程池线程数为0,则新建线程 if (isRunning(c) && workQueue.offer(command)) { int recheck = ctl.get(); if (! isRunning(recheck) && remove(command)) reject(command); else if (workerCountOf(recheck) == 0) addWorker(null, false); }
//如果加入阻塞队列失败,则尝试新建一个线程,如果失败了
//则说明线程池关闭了或者线程达到最大线程数,因此调用reject() else if (!addWorker(command, false)) reject(command); }
线程池提供了两个方法,用来关闭线程池。
(1)shutdown():不会立即关闭线程池,但也不接受新的任务,等待队列中所有任务执行完毕后关闭。
(2)shutdownNow():立即终止线程池,并尝试打断正在执行的任务,清空工作队列,返回尚未执行的任务。
线程池的线程数应该如何设置
Nthreads = Ncpu * (1 + w/c) w为阻塞时间,c为计算时间
IO密集型:w/c>1,因此线程数应该为cpu的数倍,但需要考虑线程所占内存,因此通常将线程数设置为cpu的2倍。
CPU密集型:w/c=0,因此线程数为CPU个数。通常将线程数设置为CPU+1,防止线程由于偶尔出现的原因而暂停。