常識的な仕上げ-Javaマルチスレッド

プロセスとスレッドの違い

  • プロセスはメモリスペースを排他的に占有し、それぞれの実行状態を保存し、相互に干渉せず、相互に切り替えることができるため、同時処理タスクの可能性を提供します。
  • プロセスのメモリリソースを共有し、相互に高速に切り替えることで、よりきめ細かいタスク制御がサポートされるため、プロセス内のサブタスクを同時に実行できます。

プロセスはリソース割り当ての最小単位であり、スレッドはCPUスケジューリングの最小単位です

  • プロセスに関連するすべてのリソースは、PCB(プロセス制御ブロック)に記録されます。
  • プロセスはプリエンプティブプロセッサのスケジューリングユニットです。スレッドはプロセスに属し、そのリソースを共有します。
  • スレッドは、スタックレジスタ、プログラムテクノロジ、およびTCB(スレッド制御ブロック)のみで構成されます。

プロセスとスレッドの違い

  1. スレッドは独立したアプリケーションと見なすことはできず、プロセスは独立したアプリケーションと見なすことができます
  2. プロセスには独立したアドレス空間があり、相互に影響を与えることはありません。スレッドはプロセスの異なる実行パスにすぎません。
  3. スレッドには独自のスタック変数とローカル変数がありますが、独立したアドレス空間はありません。マルチプロセスプログラムはマルチスレッドプログラムよりも堅牢です。
  4. プロセスの切り替えはスレッドの切り替えよりもコストがかかり、変数を共有することはできません

Javaプロセスとスレッドの関係

  1. Javaは、プロセスやスレッドなど、オペレーティングシステムによって提供される機能をカプセル化します。
  2. プログラムを実行すると、少なくとも1つのスレッドを含むプロセスが生成されます
  3. 各プロセスはjvmインスタンスに対応し、複数のスレッドがjvmのヒープを共有します
  4. Javaは自動的にメインスレッドを作成し、メインスレッドは子スレッドを作成できます

スレッドステータス

  1. 新規:作成後に開始されていないスレッド状態
  2. 実行可能:実行中(実行中の可能性があり、CPUが実行時間を割り当てるのを待機する可能性がある)と準備完了(CPU使用権を取得するためにスレッドスケジューリングによって選択されるスレッドプールで待機中)が含まれます
  3. 無期限に待機中(待機中):CPU実行時間は割り当てられないため、ディスプレイをスリープ解除する必要があります。
    次のメソッドにより、スレッドは無期限に待機します。
    • Timeoutパラメーターを設定するObject.wait()メソッドはありません。
    • Timeoutパラメーターを設定するThread.join()メソッドはありません
    • LockSupport.park()メソッド
  4. 期限待ち:システムは一定期間後に自動的にウェイクアップします
  5. ブロッキング:排他ロックの取得を待機中
  6. 終了:終了したスレッドの状態、スレッドは実行を終了しました

睡眠と待機の違い

  1. sleepはThreadクラスのネイティブメソッドであり、waitはObjectのネイティブメソッドです。
  2. sleep()メソッドはどこでも使用できます
  3. wait()メソッドは、synchronizedメソッドまたはsynchronizedブロックでのみ使用できます
  4. Thread.sleepはCPUを放棄するだけで、すでに占有されているロックされたリソースを解放しません。
  5. Object.waitは、CPUを放棄するだけでなく、占有されていた同期リソースロックを解放します。

notifyとnotifyAllの違い

ロックプールEntryList:
スレッドAがすでにオブジェクトのロックを所有しており、他のスレッドBがこのオブジェクトの同期メソッド(またはブロック)を呼び出したい場合、オブジェクトロックの所有権を取得する必要があり、ブロックされてオブジェクトロックを入力しますプールはロックが解除されるのを待ちます。

待機プールWaitSet:
スレッドがオブジェクトの待機()メソッドを呼び出し、スレッドAがオブジェクトロックを解放し、スレッドAがオブジェクトの待機プールに入ると仮定しますスレッドプール待機ロックは競合オブジェクトではありません

  1. notifyAll内のすべての聞かせて待機中のプールのスレッドがすべて入力されたロック・プールのロックを獲得するために競争する機会を。
  2. notifyロックを取得するために競合するロックプールのチャンスに、待機中のスレッドプール内のランダムに選択します

産出()

  1. Thread.yield()関数が呼び出されると、現在のスレッドがCPUを放棄する意思があるというヒントがスレッドスケジューラに与えられますが、スレッドスケジューラはこの暗い時間を無視する場合があります。
  2. 現在のスレッドがCPUを放棄した場合でも、CPUをプリエンプトし続けます。
  3. すでに取得されているロックを放棄しません

割り込み()

Thread.currentThread().interrupt();スレッドを中断する必要があることを通知するための呼び出し

  1. スレッドがブロック状態にある場合、スレッドはすぐにブロック状態を終了しInterruptedException、例外をスローします。
  2. スレッドが通常のアクティブ状態にある場合、スレッドの割り込みフラグはtrueに設定されます。割り込みフラグが設定されているスレッドは引き続き正常に実行され、影響を受けません。

スレッドを中断する方法。というスレッド
ニーズが呼び出されるが、割り込みに協力しなければならない
。3.タスクは常にスレッドの割り込みフラグビットを確認してください。割り込みフラグビットがセットされている場合、正常に動作している場合
、それはなります停止スレッド自体。4。スレッドが通常のアクティブ状態にある場合、このスレッドの割り込みフラグはtrueに設定されます。ただし、スレッドは正常に実行されます。

ロック

ミューテックスの特徴

相互排除:つまり、マルチスレッド調整メカニズムを実現するこの機能により、1つのスレッドのみが特定のオブジェクトロックを同時に保持できます。相互排除は操作のアトミック性とも呼ばれます
可視性:ロックが解放される前に共有変数に加えられた変更が、その後ロックを取得する別のスレッドに表示されることを確認する必要があります(つまり、最新の共有変数の値は、ロックの取得時に取得する必要があります)。

同期

同期されたJDK初期バージョン

  1. Synchronizedはヘビーウェイトロックであり、MutexLockを使用して実現します
  2. スレッド間の切り替えは、ユーザーからコアモードに変更する必要があります。これは比較的コストがかかります。

同期jdk6
は、同期の4つの状態(ロックなし、部分ロック、軽量ロック、重量ロック)を最適化します。

バイアスされたロックロックにマルチスレッドの競合がない場合)は、同じスレッドによるロックの取得コストを削減します。
基本的な考え方:スレッドがロックを取得すると、ロックはバイアスモードになります。スレッドが再度ロックを要求すると、同期操作を行う必要はありません。つまり、ロックを取得するプロセスでは、Mark Wordのロックマークビットがバイアスされたロックであり、現在のスレッドIDがMarkWordのThreadIDと等しいことを確認するだけで済みます。ロックアプリケーションに関連する多くの操作。

軽量ロックバイアスされたロックは、1つのスレッドが同期ブロックに入ると実行され、2番目のスレッドがロック競合に参加すると、バイアスされたロックが軽量ロックにアップグレードされます。シナリオ:スレッドは同期ブロックを交互に実行します

ヘビー級ロック同時にマルチスレッドの競争がある場合は、ヘビー級ロックにアップグレードしてください

ロックメモリのセマンティクス

  • スレッドがロックを解放すると、Javaメモリモデルは、スレッドに対応するローカルメモリ内の共有変数をメインメモリにフラッシュします。
  • スレッドがロックを取得すると、Javaメモリモデルはスレッドに対応するローカルメモリを無効にするため、モニターによって保護されているクリティカルセクションコードはメインメモリから共有変数を読み取る必要があります。

スピンロック

  • 多くの場合、共有データのロック状態は短時間持続し、スレッドを切り替える価値はありません。
  • CPUをあきらめることなく、スレッドにビジーループを実行させ、ロックが解放されるのを待つことによって
  • 短所:ロックが他のスレッドによって長時間占有されていると、パフォーマンスのオーバーヘッドが大きくなります。

ロックの除去

JITコンパイル中に、実行中のコンテキストをスキャンして、競合する可能性が低いロックを削除します

锁粗化

ループ本体のロックを避けてください

同期とReentrantLockの違い

  • synchronizedキーワードでReentrantLockあり、クラスです
  • ReentrantLockデッドロックを回避するために、ロックを取得するための待機時間を設定できます
  • ReentrantLockさまざまなロック情報を取得できます
  • ReentrantLock複数の通知を柔軟に実装できます(Condition
  • メカニズムは異なりsynchronizedます。オブジェクトヘッダーのマークワードが操作され、クラスのメソッドLock呼び出されます。Unsafepark()

Javaメモリモデル(JMM)

Javaメモリモデル(Javaメモリモデル):それ自体は抽象的な概念であり、実際には存在せず、一連のルールと仕様を記述します。この一連の仕様を通じて、プログラム内の各変数(インスタンスフィールド、静的フィールドを含む)のアクセス方法を定義します。および配列オブジェクトを構成する要素)
ここに画像の説明を挿入します

揮発性

jvmによって提供される軽量の同期メカニズム

  • volatileによって変更された共有変数は、常にすべてのスレッドに表示されます
  • 命令の並べ替えの最適化を防ぐ

揮発性変数がすぐに表示されるのはなぜですか?

揮発性変数を書き込む場合、JMMはスレッドに対応する作業メモリー内の共有変数をメインメモリーにフラッシュします。
揮発性変数を読み取る場合、JMMはスレッドに対応する作業メモリーをメインメモリーから無効に設定します。最新の値

揮発性が再配置の最適化をどのように禁止するか

メモリバリア

  1. 特定の操作の実行順序を保証します
  2. 特定の変数のメモリの可視性を確保する

メモリバリア命令を挿入することによりメモリバリアの前後で命令の並べ替え最適化実行することを禁止し、さまざまなCPUのキャッシュデータを強制的にフラッシュして、CPU上のすべてのスレッドがこれらのデータの最新バージョンを読み取れるようにします。

揮発性と同期の違い

  1. volatile本質は、レジスタ(作業メモリ)内の現在の変数の値が不確実であり、メインメモリから読み取る必要があることをjvmに伝えるsynchronizedことです現在の変数をロックすることであり、現在のスレッドのみが変数にアクセスできます。および他のスレッドはブロックして待機する必要があります。
  2. volatile変数レベルでのみ使用できます。synchronized変数、メソッド、およびクラスレベルで使用できます。
  3. volatile可視性のみが保証され、原子性は保証されません。synchronized可視性と原子性の両方が保証されます
  4. volatileスレッドブロッキングを引き起こしません;スレッドブロッキングsynchronizedを引き起こす可能性があります
  5. volatile命令の再配置を防ぐsynchronizedことができます変数はコンパイラによって最適化されません。の変数はコンパイラによって最適化できます。

CAS(コンペアアンドスワップ)

CASは楽観的ロックに属し、同期は悲観的ロックに属します

短所:

  1. サイクルタイムが長い場合、オーバーヘッドが高くなります
  2. 共有変数のアトミック操作のみを保証します
  3. ABA問題、解決策:使用AtomicStampedReference(内部バージョンは実際にはプラスバージョンです)

スレッドプール

ThreadPoolExecutorのコンストラクター

スレッドプール拒否戦略

ここに画像の説明を挿入します

新しいタスクが実行のために送信された後の判断

新しいタスクが実行のために送信された後の判断

スレッドプールのステータス

ここに画像の説明を挿入します
ここに画像の説明を挿入します

スレッドプールサイズの選択

  • コンピューターを集中的に使用し、CPUを消費します。通常、CPUコアの数+1またはCPUコアの数* 2
  • IOを集中的に使用し、通常はCPUコアの数/(1-0.9)またはCPUコアの数/(1-0.8)
    例:8コアプロセッサ、8 /(1-0.9)= 80ioスレッド

おすすめ

転載: blog.csdn.net/u013202238/article/details/114018836