Javaスレッドプールインタビューのすべての質問を5分で解決します

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

  1. リソース消費を削減します。作成されたスレッドを再利用することにより、スレッドの作成と破棄による消費を削減します。

  2. 応答速度を向上させます。タスクが到着すると、スレッドが作成されるのを待たずにタスクをすぐに実行できます。

  3. スレッドの管理性を向上させます。スレッドは希少なリソースです。無制限に作成すると、システムリソースを消費するだけでなく、システムの安定性も低下します。スレッドプールは、統合された割り当て、調整、および監視に使用できます。

2.ThreadPoolExecutorスレッドプールクラスの7つのパラメーターの詳細な説明

パラメータ 説明
corePoolSize コアスレッドの数、スレッドプールが維持するスレッドの最小数
maximumPoolSize スレッドプールによって維持されるスレッドの最大数
keepAliveTime スレッドプール内のコアスレッド以外のスレッドの最長アイドル時間、およびこの時間を超えるアイドルスレッドは破棄されます
単位 keepAliveTimeの単位、TimeUnitのいくつかの静的属性:NANOSECONDS、MICROSECONDS、MILLISECONDS、SECONDS
workQueue スレッドプールによって使用されるタスクバッファキュー
threadFactory スレッドの作成に使用されるスレッドファクトリは、通常、デフォルトを使用します
ハンドラ 拒否されたタスクに対するスレッドプールの処理戦略

スレッドプールタスクを処理できない場合は、ハンドラーで指定された戦略で処理できます。

ThreadPoolExecutorは、次の4つの戦略を提供します。

  1. ThreadPoolExecutor.AbortPolicy:タスクを放棄し、RejectedExecutionExceptionをスローします。これはデフォルトの処理メソッドでもあります。
  2. ThreadPoolExecutor.DiscardPolicy:例外をスローせずにタスクを破棄します
  3. ThreadPoolExecutor.DiscardOldestPolicy:キュー内の最初のタスクを破棄してから、タスクの実行を再試行します(このプロセスを繰り返します)
  4. ThreadPoolExecutor.CallerRunsPolicy:タスクは呼び出し元のスレッドによって処理されます

処理方法は、RejectedExecutionHandlerインターフェースを実装することでカスタマイズできます。

3、スレッドプールタスクの実行

1.実行タスクを追加します

  • submit()このメソッドは、戻り値を持つスレッドを実行できるFutureオブジェクトを返します。または、いつでもキャンセルしたいスレッドを実行できます。Futureオブジェクトのget()メソッドは戻り値を取得します。Futureオブジェクトのcancel(true / false)はタスクをキャンセルし、タスクが開始されていないか完了している場合はfalseを返し、パラメーターは実行中のスレッドを中断するかどうかを示します。
  • execute()には戻り値がありません。

2.スレッドプールタスクの送信プロセス

2.1。この時点でスレッドプールの数がcorePoolSize未満の場合、スレッドプール内のスレッドがアイドル状態であっても、追加されたタスクを処理するために新しいスレッドを作成する必要があります。
2.2。この時点でスレッドプールの数がcorePoolSizeと等しいが、バッファキューのworkQueueがいっぱいない場合、タスクはバッファキューに入れられます。
2.3。スレッドプールの数がcorePoolSize以上で、バッファーキューのworkQueueがいっぱいで、スレッドプールの数がmaximumPoolSize未満の場合、追加されたタスクを処理するための新しいスレッドが作成されます。
2.4。スレッドプール内の数がcorePoolSizeより大きい場合、バッファーキューworkQueueがいっぱいであり、スレッドプール内の数がmaximumPoolSizeに等しい場合、タスクはハンドラーによって指定れた戦略によって処理されます
2.5。スレッドプール内のスレッド数がcorePoolSizeより大きい場合、スレッドのアイドル時間がkeepAliveTimeを超えると、スレッドは終了します。このようにして、スレッドプールはプール内のスレッド数を動的に調整できます。

要約すると、タスク判定の処理の優先順位は、コアスレッドcorePoolSize、タスクキューworkQueue、および最大スレッドmaximumPoolSizeです。3つすべてがいっぱいの場合は、ハンドラーを使用して拒否されたタスクを処理します。

注意:

  1. workQueueが×××制限キューを使用する場合、maximumPoolSizeパラメーターは、new LinkedBlockingQueue()やnew ArrayBlockingQueue(Integer.MAX_VALUE)などの意味がなくなります。
  2. SynchronousQueueキューを使用する場合、キューには容量がないため、タスクはキューに入れられません。スレッドプールにアイドル状態のスレッドがない場合、タスクを受信するための新しいスレッドがすぐに作成されます。maximumPoolSizeを大きく設定する必要があります。
  3. コアスレッドの数と最大スレッドの数が等しい場合、KeepAliveTimeは効果がありません。

3.スレッドプールが閉じられます

3.1。shutdown()は新しいタスクを受け入れず、追加されたタスクを処理し
ます3.2。shutdownNow()は新しいタスクを受け入れず、追加されたタスクを処理せず、処理中のタスクを中断します

4.共通キューの概要

4.1 ArrayBlockingQueue:これはある。有界ブロッキングキュー配列によって実装固定容量を持つ
4.2 SynchronousQueue:能力がなければ、データをキャッシュすることはできません。各プットは、テイクを待たなければなりません;ときのオファー()、他のスレッドが存在しない場合。 poll()またはtake()ではfalseを返します。
4.3。LinkedBlockingQueue:これは、単一リンクリストによって実装されるデフォルトの×××ブロッキングキューです。LinkedBlockingQueueは、オプションの制限付きコンストラクターを提供します容量指定されていない場合、容量はデフォルトでInteger.MAX_VALUEになります

キュー操作:

方法 説明
追加 元土を追加します。キューがいっぱいの場合は、例外をスローします
削除する キューの先頭にある要素を削除して返します。キューが空の場合、例外がスローされます
提供 要素を追加してtrueを返します。キューがいっぱいの場合はfalseを返します
投票 キューの先頭にある要素を削除して返します。キューが空の場合はnullを返します
置く 要素を追加します。キューがいっぱいの場合はブロックします
取る キューの先頭にある要素を削除して返します。キューが空の場合は、ブロックします
素子 キューの先頭にある要素を返します。キューが空の場合、例外がスローされます
ピーク キューの先頭にある要素を返します。キューが空の場合はnullを返します

5.エグゼキュータスレッドファクトリクラス

1. Executors.newCachedThreadPool();
説明:キャッシュ可能なスレッドプールを作成します。スレッドプールの長さが処理要件を超える場合、アイドル状態のスレッドを柔軟にリサイクルできます。リサイクルがない場合は、新しいスレッドを作成できます。
内部実装: new ThreadPoolExecutor(0、Integer。MAX_VALUE、60L、TimeUnit.SECONDS、new SynchronousQueue <runnable>()); </ runnable>

2. Executors.newFixedThreadPool(int);
説明:固定長のスレッドプールを作成しますこれにより、最大同時スレッド数を制御でき、超過したスレッドはキューで待機します。
内部実装:new ThreadPoolExecutor(nThreads、nThreads、0L、TimeUnit.MILLISECONDS、new LinkedBlockingQueue <runnable>()); </ runnable>

3. Executors.newSingleThreadExecutor();
説明:シングルスレッドスレッドプールを作成しますタスクの実行には単一のワーカースレッドのみを使用し、すべてのタスクが順番に実行されるようにします。
内部実装:新しいThreadPoolExecutor(1,1,0L、TimeUnit.MILLISECONDS、new LinkedBlockingQueue <runnable>())</ runnable>

4. Executors.newScheduledThreadPool(int);
説明:タイミングと定期的なタスク実行をサポートするために、固定長のスレッドプールを作成します。
内部実装:新しいScheduledThreadPoolExecutor(corePoolSize)

[添付]スレッドプール仕様を使用するためのAlibabaJava開発マニュアル

  1. [必須]スレッドまたはスレッドプールを作成するときは、エラーが発生した場合のバックトラックを容易にするために、意味のあるスレッド名を指定してください。
    良い例:

    public class TimerTaskThread extends Thread {
    public TimerTaskThread(){
        super.setName("TimerTaskThread"); 
        ...
    }
    }
  2. [必須]スレッドリソースはスレッドプールを介して提供する必要があり、アプリケーションで明示的にスレッドを作成することは許可されていません。
    注:スレッドプールを使用する利点は、スレッドの作成と破棄に費やされる時間とシステムリソースのオーバーヘッドを削減し、リソース
    不足の問題を解決することですスレッドプールが使用されていない場合、システムが同じタイプのスレッドを多数作成し、メモリ不足または
    「オーバースイッチング」の問題を引き起こす可能性あります

  3. [必須]スレッドプールはエグゼキューターを使用して作成することはできませんが、ThreadPoolExecutorを介して作成されます。この
    処理方法により、学生はスレッドプールの操作ルールをより明確に記述し、リソース枯渇のリスクを回避できます。

説明:エグゼキューターによって返されるスレッドプールオブジェクトの欠点は次のとおりです
。1)FixedThreadPoolおよびSingleThreadPool:
許可される要求キューの長さはInteger.MAX_VALUEであり、これにより多数の要求が蓄積され、OOMが発生する可能性があります。
2)CachedThreadPoolおよびScheduledThreadPool:
作成できるスレッドの数はInteger.MAX_VALUEです。これにより、多数のスレッドが作成され、OOMが発生する可能性があります。

6.まとめ

ThreadPoolExecutorは、さまざまな使用シナリオに適したいくつかのコアパラメーターを介してさまざまなタイプのスレッドプールを定義します。その中で、タスクが送信されると、corePoolSize、workQueque、maximumPoolSizeが順番に決定され、さまざまな状態が異なる方法で処理されます。

コアパラメータの構成基準

1.1、コアスレッドの数corePoolSize

コアスレッド数の設計は、タスクの処理時間と1秒あたりに生成されるタスクの数に応じて決定する必要があります。たとえば、タスクの実行には0.1秒かかり、システムは1秒あたり100個のタスクを生成します。 80%の確率で、この100個のタスクを1秒間に処理するには、10個のスレッドが必要です。現時点では、コアスレッドの数を10個に設計できます。当時の実際の状況は不可能でした。非常に平均的であるため、一般的には2080の原則に従って、つまりパーセンテージに従って設計できます。80の場合、コアスレッドの数が設計され、残りの20%は最大数で処理できます。スレッド。

1.2、タスクキューの長さ(workQueue)

タスクキューの長さは、通常、コアスレッド数/単一タスクの実行時間* 2(タスクの最大待機時間)として設計されます。たとえば、上記のシナリオでは、コアスレッドの数は次のように設計されています。 10であり、単一タスクの実行時間は0.1であるため、キューの長さは200に設計できます。

1.3、スレッドの最大数(maximumPoolSize)

最大スレッド数の設計では、コアスレッド数の条件を参照するだけでなく、システムによって1秒あたりに生成されるタスクの最大数も参照する必要があります。たとえば、上記の環境では、システムによって1秒あたりに生成されるタスクの最大数は1000であり、最大スレッド数=(タスクの最大数-タスクキューの長さ)*単一タスクの実行時間;両方の最大スレッド数=(1000-200 )* 0.1 = 80;もちろん、スレッドの最大数もサーバーのハードウェア構成と関係があります。

 

おすすめ

転載: blog.csdn.net/qq_27828675/article/details/115357347
おすすめ