プール内の「Java並行プログラミングの芸術」第9章Javaスレッド

 プール内の第9章Javaスレッド

開発中に、スレッドプールの使用の合理化は、3つの利益をもたらすことができます。

  1. リソース消費を削減します。スレッドを再利用することにより、消費に起因するスレッドの作成と破壊を軽減するために作成されています。
  2. 応答速度を向上させます。ミッションが到着すると、タスクは、スレッドの作成を直ちに実施することが可能になるまで待つ必要がないかもしれません。
  3. スレッドには、管理性を向上させます。無制限の作成は、だけでなく、システムリソースを消費するだけでなく、流通、チューニングや監視を統一することができますスレッドプールを使用して、システムの安定性を減らす場合、スレッドは、希少資源です。

原則9.1スレッドプール

  スレッドプールのスレッドプールのプロセスに新しいタスクを提出するときは、次のとおりです。

1)スレッドプールは、コアスレッドプールスレッドが任務上にあるかどうかを決定します。ない場合は、タスクを実行するための新しいワーカースレッドを作成します。コアスレッドプールのスレッドがミッションにしている場合は、次のプロセスに入ります。

2)作業キュースレッドプールが満杯になったかを決定。作業キューが満杯でない場合は、タスクが新たに投入されたジョブキューに格納されます。作業キューがいっぱいになっている場合は、次のプロセスに入ります。

3)スレッドプールスレッドプールのスレッドがすべての条件を働いているかを決定。ない場合は、タスクを実行するための新しいワーカースレッドを作成します。完全な場合には、飽和戦略にこのタスクに対処します。

 

ThreadPoolExecutor方法は、以下の4つのサブケースを行い、実行します。

  1. スレッドが現在のタスクを実行するための新しいスレッドを作成し、corePoolSizeよりも実行されている場合(この手順の実装はグローバルロックを取得する必要があることに注意してください)。
  2. 実行中のスレッドがcorePoolSize以上である場合、タスクはBlockingQueueのに参加します。
  3. あなたは(キューが満杯である)タスクのBlockingQueueに参加できない場合は、タスクを処理する新しいスレッドを作成します(この手順の実装は、グローバルロックを取得する必要があることに注意してください)。
  4. あなたが現在maximumPoolSizeを超えるスレッドを実行する新しいスレッドを作成した場合、タスクが拒否され、RejectedExecutionHandler.rejectedExecution()メソッドを呼び出します。
公共 のボイドの実行(Runnableをコマンド){
     IF(コマンド== nullのスロー 新しい新しいのNullPointerException();
         // スレッドの数は、基本的なスレッド、スレッドの作成と、現在のタスクの実行の数より少ない場合
    IF(プールサイズ> = corePoolSize ||!addIfUnderCorePoolSize(コマンド)){
         // スレッドの数がスレッドの作成におけるスレッドの基本的な数以上で、作業キューに現在のタスクが失敗しています。
        IF(runState RUNNING == && workQueue.offer(コマンド)){
             IF(runState!= ||プールサイズRUNNING == 0 
                ensureQueuedTaskHandled(コマンド);
        }
        // スレッドプールが動作していないか、タスクがキューに入れることができず、スレッドの現在の数は、スレッドの最大許容数に満たない場合は、
         // タスクを実行するスレッドを作成します。
         のIF(!addIfUnderMaximumPoolSize(コマンド))
         //は例外RejectedExecutionExceptionをスロー 
            (コマンド)を拒否; //は、シャットダウンや飽和しています
        }
}

 

スレッドプールのスレッドが2つの場合にタスクを実行するには:

  1. あなたはexecute()メソッド内のスレッドを作成すると、スレッドが現在のタスクを実行します。
  2. あなたが現在のタスクでこのスレッドを実行した後、タスクが実行するために取得するのBlockingQueueから繰り返されます。

 スレッドプールの使用9.2

スレッドプールの作成9.2.1

 新しい ThreadPoolExecutorint型 corePoolSize、int型 maximumPoolSize、長い keepAliveTimeが、TimeUnitでユニット、BlockingQueueの<Runnableを>ワークキュー、ThreadFactory threadFactory、のRejectedExecutionHandlerハンドラ)。
  • corePoolSize(基本的なスレッドプールのサイズ):スレッドプールにタスクを提出する際、スレッドプールは他のフリーの基本的なスレッドが新しいタスクを実行することができた場合でも、タスクを実行するスレッドを作成します、あなたが実行する必要のあるタスクの数がより大きくなるまで、スレッドを作成することになりますスレッドプールのサイズを作成することはもはや必要不可欠ではありません。あなたがスレッドプールprestartAllCoreThreads()メソッドを呼び出すと、スレッドプールは、事前に作成され、すべての基本的なスレッドを開始します。
  • runnableTaskQueue(タスクキュー):セーブ阻止するためのタスクの実行キューを待ちます。次のブロッキングキューを選択することができます。
    • ArrayBlockingQueueこのキューFIFO(先入れ先出し)原則ソート要素のブロックキューアレイベースの構成:。
    • LinkedBlockingQueue:リスト構造に基づいてキュー、一定ArrayBlockingQueueより通常高いこのソート要素のためのFIFOキューを、阻止します。静的ファクトリメソッドExecutors.newFixedThreadPool()このキューを使用しています。
    • SynchronousQueue:ブロッキングキュー要素が格納されていません。各挿入操作が別のスレッドが削除操作を呼び出すまで待つか、または操作がブロックされた状態にあった挿入する必要があり、スループットは、静的ファクトリメソッドは、このキューを使用Executors.newCachedThreadPoolリンク-のBlockingQueueよりも通常は高いです。
    • PriorityBlockingQueue:優先キューは無制限の障害物を持っています。
  • maximumPoolSizeスレッド・プールの最大数):スレッドプールを使用すると、スレッドの最大数を作成することができます。キューがいっぱいになると、スレッドの最大数よりも少ないが作成されているスレッドの数と、スレッド・プールには、タスクを実行するために、新しいスレッドを再作成しますあなたが効果なしに無制限のタスクキューにこのパラメータを使用する場合は、。
  • ThreadFactory:スレッドを作成するために工場を設定するために使用されます。あなたは工場の外に作成されたスレッドによって各スレッドに、より意味のある名前を設定することができます。オープンソースのフレームワークグアバは、意味のある名前を設定するスレッドプールのスレッドに迅速ThreadFactoryBuilderを提供しています。新しいThreadFactoryBuilder()setNameFormat(「 XX-task-%d個」)ビルドを(); ..
  • RejectedExecutionHandler(飽和戦略):スレッドとキューがフルタイムである、すなわちとき、どのような戦略は、新しいタスクの提出に対処するために採用されなければなりません。デフォルトの戦略はAbortPolicy(例外をスロー)で、他の戦略があります(のみ、呼び出し元のスレッドがタスクを実行するために)CallerRunsPolicy、DiscardOldestPolicyは(最近のタスクをキューイング破棄し、現在のタスクを実行する)、DiscardPolicy(無治療、廃棄されました)
    • AbortPolicy:直接投げます。
    • CallerRunsPolicy:のみ、呼び出し元のスレッドがタスクを実行します。
    • DiscardOldestPolicy:最近のタスクをキューイングし、現在のタスクを実行して捨てます。
    • DiscardPolicy:無治療、廃棄されました。

9.2.2は、スレッドプールにジョブを送信します

   あなたは、それぞれ、スレッドプールにタスクを提出する2つのメソッドを使用することができ、実行()()提出方法を。

  • ジョブを送信するために使用さexecute()メソッドが戻り値を必要としない、タスクが正常にプールスレッドで実行されているかどうかを決定することは不可能です
// タスクを入力するexecute()メソッドは、クラスのRunnableのインスタンスである 
threadsPool.execute(新しい新しいRunnableを(){
    @オーバーライド
    公共 ボイドラン(){
     // TODO自動生成方法スタブ
    }
});
  • 必要な戻り値のタスクを提出するために使用される()メソッドを提出します。スレッドプールは、将来のタスクが正常に実行されることにより、判断することができるオブジェクトの未来型のオブジェクトを返しますそして、メソッドは値を返し、タスクが完了するまで、(長いタイムアウト、TimeUnitで単位)を取得使用し、現在のスレッド()メソッドのブロックを取得する方法があり、この時間ながら、現在のスレッドAを遮断した直後に戻ります)(GETの将来を介して取得することができますタスクが実行されていない可能性があります。
将来の<Object>未来= executor.submit(harReturnValuetask)。
    してみてください{
        物体S = future.get()。
    } キャッチ(InterruptedExceptionあるE){
         // 割り込み例外 
    } キャッチ(ExecutionException E){
         // 処理タスクを実行することができる異常 
    } 最後に{
         // 閉じるスレッドプール
        executor.shutdown()。
    }
}

9.2.3スレッドプールを閉じます

  スレッドプールの呼び出しによってシャットダウン または  shutdownNowのを スレッドプールの方法を閉じます。

   トラバーススレッドプールのワーカースレッド、その後、一つずつのスレッドがスレッドを中断するinterruptメソッドを呼び出して、私はタスクを終了しないことがあり、割り込みに応答することはできません:その原理があります。しかし、彼らは、特定の相違点は次のとおりです。

  • スレッドプールの最初の状態に設定されてshutdownNowのSTOP、その後に試みる行ってタスクまたは休止の全てを通知し、実行を待っているタスクのリストを返し糸
  • スレッドプールのシャットダウンだけ状態がに設定されたSHUTDOWNの状態、そしてすべてのタスクを実行していないスレッドを中断

   これらのメソッドの呼び出しのいずれかが閉じられるように、isShutDown方法は限り真を返します。すべてのタスクを閉じたときに、isTerminaedメソッドがtrueを返す呼び出して、スレッド・プールが正常に閉じていることを示しています。

  通常、あなたが終了したタスクを実行するために持っていない場合、あなたはshutdownNowのメソッドを呼び出すことができ、スレッドプールを閉じるために、シャットダウンメソッドを呼び出します

 スレッドプールの合理的な配分を9.2.4

1、タスクの性質:

  • CPU集約型タスク:例えば、Nに設定するなど、可能な限り小さく、スレッド、CPUスレッドプール内の1つのスレッドを。
  • IO集約型のタスク:IO集約型のタスクのスレッドは、常にミッションにされていないが、あなたは、このようなN * 2のように多くのスレッド、設定する必要がありますCPUを
  • 混血タスク:分割は、CPU集約型タスクと1つのIO集約型のタスクに分割した場合は、タスクの実行時間は、限り、両者の差が大きすぎないよう、スループットは分解が連続した後に実行されるよりも高いであろうスループットを実行。2つのタスクの実行時間の差が大きすぎる場合、それは分解のために必要ではありません。()。AvailableProcessors()メソッドは、CPU番号Runtime.getRuntimeにより現在のデバイスを得ることができます

2、の優先タスク:高、中、低。

  • 異なる優先度のタスクがに対処するためのプライオリティキューPriorityBlockingQueueを使用することができます。これは、優先度の高いタスクが実行できるようになります。[注:キューに提出し、優先度の高いタスクとなっている場合には、優先度の低いタスクが実行されないことがあります。

3、タスクの実行時間:ロング、セミロング、ショート。

  • 処理するためにスレッドプールの異なる時間スケールに異なるタスクを実行することができ、または実行時間は、タスクの実行前に短くなるように、あなたは、プライオリティキューを使用することができます。

図4に示すように、タスク依存:そのようなデータベース接続のような他のシステムリソースに依存するかどうか。

  • 依存タスクデータベース接続プール SQLスレッドが提出されたため、結果を返すために、データベースを待つ必要の後、待ち時間、長いCPUのアイドル時間が長い、スレッド数を大きく設定する必要があります CPUのより有効に活用するために、

9.2.5監視スレッドプール

あなたは、スレッドプールの監視時間で次のプロパティを使用することができます。

  • taskCount:スレッドプールは、実行するタスクの数を必要とします。
  • completedTaskCount:動作中のスレッドプール内のタスクの数が完了したが、以下taskCountに等しいです。
  • largestPoolSize:スレッドプール内のスレッドの最大数は、以前に作成されています。このデータを通じて、あなたは、スレッド・プールがいっぱいで知ることができます。値は、スレッドプールの最大サイズに等しい場合、スレッドプールが充填されていました。
  • getPoolSize:スレッドプール内のスレッド数。スレッドプールが破壊されていない場合は、スレッドプールのスレッドは自動的に破棄されませんので、このサイズでは唯一上昇します。
  • getActiveCountは:アクティブなスレッドの数を取得します。

  スレッドプールを拡張することによって監視しました。あなたも監視すべきいくつかのコードを実行閉じた後に、スレッドプールの実装前に、前のタスクを実行することができ、beforeExecute、afterExecuteと終了スレッドプールメソッドを書き換え、継承によってスレッドプールのスレッドプールをカスタマイズすることができます。例えば、平均実行時間は、タスク、最大実行時間、最小実行時間を監視します。
スレッドプール内のこれらのメソッドは空のメソッドです。

保護された ボイド beforeExecute(スレッドT、RunnableをR){}

 

おすすめ

転載: www.cnblogs.com/toria/p/bingfa9.html