[Java 面接の質問] マルチスレッド

記事ディレクトリ

オリジナル

原文: https://www.yuque.com/unityalvin/baguwen/xbg8ds

1. プロセスとは

バックグラウンドで実行されているすべてのプログラムはプロセスです

2. スレッドとは

スレッドは、オペレーティング システムが操作のスケジューリングを実行できる最小単位です。これはプロセスに含まれており、プロセス内の実際の操作単位となります。

3. 同時実行性と並列性とは何ですか

並列とは、2 つ以上のイベントが同時に発生することを意味し、同時実行とは、2 つ以上のイベントが同じ時間間隔で発生することを意味します。

4. マルチスレッドを使用する理由

コンピュータの底部から: スレッドは、プログラム実行の最小単位である軽量プロセスにたとえることができ、スレッド間の切り替えとスケジューリングのコストは、プロセスのコストよりもはるかに小さくなります。また、マルチコア CPU の時代により、複数のスレッドを同時に実行できるため、スレッド コンテキストの切り替えのオーバーヘッドが軽減されます。

現在のインターネット開発トレンドの観点から: 現在のシステムでは、数百万、さらには数千万の同時実行が必要であり、マルチスレッド同時プログラミングは、同時実行性の高いシステムを開発するための基礎です。マルチスレッド メカニズムをうまく利用すると、システム全体の同時実行性、機能とパフォーマンス。

5. マルチスレッドを使用するとどのような問題が発生する可能性がありますか?

マルチスレッドを使用する目的は、プログラムの実行効率と実行速度を向上させることですが、これはマルチスレッドが万能であるという意味ではありません。マルチスレッドを使用する過程で、メモリ リーク、デッドロック、スレッドのセキュリティの確保など、多くの問題が発生する可能性があります。等

6. スレッドのライフサイクルとステータスについて話す

  1. スレッドが作成されると NEW (新規) 状態になります。
  2. start() メソッドを呼び出して実行を開始すると、スレッドは READY (準備完了) 状態になります。
  3. 準備ができたスレッドは、CPU タイム スライス (timeslice) を取得した後、RUNNING (実行中) 状態になります。
  4. スレッドが wait() メソッドを実行すると、スレッドは WAITING (待機) 状態になります。待機状態に入ったスレッドは、実行状態に戻るために他のスレッドからの通知に依存する必要があります。
  5. sleep(long millis) メソッドまたは wait(long millis) メソッドを通じて、スレッドを TIME_WAITING (タイムアウト待機) 状態に設定できます。これは、待機状態にタイムアウト期間を追加するのと同じです。準備完了状態に戻る
  6. スレッドが同期メソッドを呼び出すときに、ロックが取得されていない場合、スレッドは BLOCKED (ブロックされた) 状態になります。
  7. Runnable の run() メソッドの実行後、スレッドは TERMINATED 状態になります。

Thread.State 列挙クラスでは次のようになります。
ここに画像の説明を挿入

7. start() メソッドが呼び出されるときに run() メソッドが実行されるのはなぜですか? run() メソッドを直接呼び出すことができないのはなぜですか?

start() は、スレッドの対応する準備作業を実行し、その後、実際のマルチスレッド作業である run() メソッドの内容を自動的に実行します。

run() メソッドを直接実行すると、 run() メソッドはメインスレッドで通常のメソッドとして実行され、特定のスレッドで実行されるわけではないため、これはマルチスレッド作業ではありません。

8. コンテキストスイッチとは何ですか

現在のタスクは、CPU タイム スライスの実行後に別のタスクに切り替える前にその状態を保存するため、次回このタスクに切り替えるときにこのタスクの状態を再度ロードできます。タスクの保存から再ロードまでのプロセスはコンテキスト スイッチです。

9. スレッドデッドロックとは何ですか

デッドロックとは、実行処理中にリソースの競合により複数のスレッドが待ち状態となり、複数のスレッドが同時にブロックされ、プログラムが正常に終了できなくなる現象を指します。

10. デッドロックが発生する理由 (4)

デッドロックは次の 4 つの条件を満たす必要があります。

  1. 相互に排他的な条件: リソースは一度に 1 つのスレッドによってのみ占有されます。
  2. 要求と保持の条件: リソースの要求によりプロセスがブロックされた場合、取得したリソースは手放されません。
  3. 非剥奪条件: スレッドによって取得されたリソースは、使い果たされる前に他のスレッドによって強制的に剥奪されることはできず、リソースは使い果たされて初めて解放されます。
  4. 循環待機条件: 複数のプロセス間で、先頭から末尾までの循環待機リソース関係が形成されます。

11. スレッドデッドロックを回避する方法(3)

  1. 破棄リクエストと保持条件: すべてのリソースに一度に適用されます。
  2. 非剥奪条件の破棄: 一部のリソースを占有しているスレッドがさらに他のリソースを申請するときに、アプリケーションを取得できない場合は、スレッドが占有しているリソースを積極的に解放できます。
  3. 循環待機状態の破壊: リソースを順番に申請することで防止します。特定の順序でリソースを申請し、逆の順序でリソースを解放します。

12. デッドロックの解決方法

  1. まず、jps コマンドを使用してスレッド番号を見つけます。
  2. 次に、jstack を使用してデッドロックを見つけます

13. 公平なロックと不公平なロックとは何ですか

● 公平なロックとは、キューイングと同様に、ロックを適用した順序で複数のスレッドがロックを取得することを意味し、次のようなものです。 ReentrantLock を true に設定 ● 不公平なロックとは、同時実行性が高い場合に
、スレッドが最初にロックを取得し、複数のスレッドがロックを取得する順序は、ロックを適用する順序に従っていないため、次のような優先順位の逆転や枯渇が発生する可能性があります。同期済み、デフォルトが false の ReentrantLock

14. リエントラントロックとは何ですか

● リエントラントロックは、同じスレッドを参照して再帰ロックとも呼ばれ、外側の関数がロックを取得した後も、内側の再帰関数はロックのコードを取得できます。
● ReentrantLock / synchronized は典型的なリエントラント ロックであり、リエントラント ロックの最大の機能はデッドロックを回避することです。

15. 悲観的ロックと楽観的ロックとは何ですか?

  • 楽観的ロック: 楽観的ロックは、他の人が同時にデータを変更しないと考えて、データを操作するときに非常に楽観的です。したがって、オプティミスティック ロックはロックせず、更新中に他の人がデータを変更したかどうかだけを判断します。他の人がデータを変更した場合は操作を中止し、そうでない場合は操作を実行します。
  • 悲観的ロック: 悲観的ロックは、データを操作するときに、他の人が同時にデータを変更すると考えて、より悲観的になります。そのため、データ操作時には直接ロックがかかり、操作が完了するまでロックは解除されず、ロック期間中は他人がデータを変更することはできません。

16. 悲観的ロックと楽観的ロックはどのように選択しますか?

今日の高同時実行性、高パフォーマンス、高可用性の環境では、オプティミスティック ロックは実際にはロックされず、効率が高いため、一般にオプティミスティック ロックがより頻繁に使用されます。更新は失敗しますが、悲観的ロックやデータベース ロックに依存する場合と比較すると、効率は低くなりますが、優れています。

17. スピンロックとは何ですか

これは、ロックを取得しようとしているスレッドがすぐにブロックされず、周期的にロックを取得することを意味します。これの利点は、スレッド コンテキストの切り替えの消費を削減することです。欠点は、ループが CPU を消費することです。
ここに画像の説明を挿入

18. 排他ロック(書き込み)と共有ロック(読み取り)とは何ですか

排他的ロック: ロックは一度に 1 つのスレッドのみが保持できることを意味します。ReentrantLock と synchronized は両方とも排他的ロックです。

共有ロック: ロックを複数のスレッドで保持できることを意味します

19. 読み取り/書き込みロックを使用する理由

同時実行性の要件を満たすためには、複数のスレッドがリソース クラスを同時に読み取ることができる必要がありますが、1 つのスレッドが共有リソースに書き込みたい場合は、現時点では他のスレッドがリソースの読み取りまたは書き込みを行うことができないようにする必要があります。 。

20. sleep() メソッドと wait() メソッドの違いと類似点について教えてください。

● 2 つの主な違いは、sleep() メソッドはロックを解放しませんが、wait() メソッドはロックを解放します。
● どちらもスレッドの実行を一時停止できます。
● wait() は通常、スレッド間の対話/通信に使用され、sleep() は通常、実行の一時停止に使用されます。
● wait() メソッドが呼び出された後、スレッドは自動的にウェイクアップしないため、他のスレッドは同じオブジェクトの Notice() メソッドまたは NotifyAll() メソッドを呼び出す必要があります。sleep() メソッドが実行されると、スレッドは自動的に起動します。または、wait(long timeout) を使用して、タイムアウト後にスレッドを自動的に起動することもできます。

21. 同期キーワードの理解について話す

synchronized キーワードは、複数のスレッド間でのリソースへのアクセスの同期を解決し、いつでも 1 つのスレッドだけが、そのスレッドによって変更されたメソッドまたはコード ブロックを実行できるようにすることができます。

Java の以前のバージョンでは、同期は重いロックであり、非効率的でした。

22. 以前の同期が非効率だったのはなぜですか?

Java 仮想マシンの同期は、Monitor オブジェクト (モニターまたはモニター ロックとも呼ばれます) の出入りに基づいて実装され、モニター ロック (モニター) は、基礎となるオペレーティング システムの Mutex ロックに依存して実装されます。スレッドはオペレーティング システムのネイティブ スレッドにマップされます。スレッドを一時停止またはウェイクアップする場合は、それを完了するためにオペレーティング システムの助けが必要であり、スレッド間で切り替えるときにオペレーティング システムはユーザー モードからカーネル モードに切り替える必要があります。これらの状態間の移行には比較的長い時間がかかります。時間と時間コストが比較的高い。

しかし、JDK1.6 以降、Java 関係者は、ロック操作のオーバーヘッドを削減するために、スピン ロック、適応スピン ロック、ロックの削除、ロックの粗密化、バイアスされたロック、軽量ロック、その他のテクノロジなどの同期を JVM レベルから大幅に最適化しました。

23. JDK1.6以降、同期により最適化されたものは何ですか?

  • まず、ロックを再分類し、低レベルから高レベルに、ロックなし状態 -> 偏ったロック状態 -> 軽量ロック状態 -> 重量ロック状態、

  • バイアス ロック
    ● バイアス ロックはスレッド用であり、スレッドがロックを取得した後は、ロック解除などの操作が行われないため、オーバーヘッドを大幅に節約できます。
    ● JDK1.6 以降ではバイアス ロックがデフォルトで有効になっていますが、プログラムの起動後数秒経過するまでは有効になりません。これを使用して-XX:BiasedLockingStartupDelay=0、バイアスされたロックの起動遅延を閉じることができます。または、これを使用して -XX:-UseBiasedLocking=falseバイアスされたロックを閉じることができます。閉じた後、プログラムは直接軽量ロック状態に入ります。
    ● 1 つのスレッドのみがアクセスする同期シナリオに適しています。

  • 軽量ロック
    ● 2 つのスレッドがロックを競合している場合、偏ったロックは無効となり、この時点でロックが拡張され、軽量ロックにアップグレードされます。ブロックされないため、プログラムの応答速度は向上しますが、競合するスレッドが取得されていない場合、ロックがスピンして CPU を消費します
    ● 低遅延、高速同期、および非常に高速な実行のシナリオに適しています

  • ヘビーウェイト ロック
    ● ロック競合期間中、ロックが取得されない場合、ロックは回転せず、スレッドを直接ブロックします
    ● 高スループット、高速同期、低速実行速度のシナリオに適しています

24. synchronized キーワードはどのように使用しますか? (3)

  1. 変更されたインスタンス メソッド
    ○ 現在のオブジェクト インスタンスをロックするように動作し、同期コードを入力する前に現在のオブジェクト インスタンスのロックを取得します。
    ○ synchronized void method() { //ビジネス コード}
  2. 静的メソッドを変更する
    ○ つまり、クラスのすべてのオブジェクト インスタンスに作用する現在のクラスをロックし、同期コードを入力する前に現在のクラスのロックを取得します。
    ○ synchronized static void method() { //ビジネスコード}
  3. 変更されたコード ブロックはロック オブジェクトを指定します
    。 ○ 指定されたオブジェクト/クラスをロックします。同期されたコードベースに入る前に、指定されたオブジェクトのロックを取得することを示します。
    ○ synchronized(this) { //ビジネスコード}

25. 同期で構築方法を変更できますか?

いいえ、コンストラクター自体は安全なので、同期されたコンストラクターなどはありません。

26. 同期の基本原理について話す

synchronized 同期ステートメント ブロックの実装では、monitorenter 命令とmonitorexit 命令を使用します。monitorenter 命令は同期コード ブロックの先頭を指し、monitorexit 命令は同期コード ブロックの末尾を指します。

synchronized によって変更されたメソッドには、monitorenter 命令とmonitorexit 命令がありませんが、代わりに、メソッドが同期メソッドであることを示す ACC_SYNCHRONIZED フラグがあります。

しかし、両方の本質はモニターモニターを入手することです。

27. synchronized と ReentrantLock の違いについて話します (5)

オリジナル曲

● synchronized はキーワードであり、JVM レベルに属します
● ReentrantLock は特定のクラス (java.util.concurrent.locks.lock) であり、API レベルのロックです

手順

● Synchronized では、ユーザーがロックを手動で解放する必要はありません。同期されたコードが実行されると、システムはサイトでロックの占有を自動的に解放します。 ● ReentrantLock では、ユーザーが手動でロックを解放する必要があります。ロックがアクティブでない場合は
、解放されるとデッドロックが発生する可能性がある 現象、try/finally ステートメントと連携するには lock() メソッドとunlock() メソッドが必要です

中断可能ですか

● synchronized は、例外がスローされるか、通常の操作が完了しない限り中断できません。
● ReentrantLock は中断でき、タイムアウト メソッド tryLock(long timeout, TimeUnit ) を設定し、LockInterruptibly() をコード ブロックに配置し、interrupt() メソッドを使用できます。呼ばれる

ロックは公平です

● 同期された不公平なロック
● ReentrantLock 両方が使用可能、デフォルトは false 不公平なロック、コンストラクターは true/false を渡すことができます。

複数の条件をバインドするロック (Condition)

● 同期 いいえ
● ReentrantLock は、グループで起動する必要があるスレッドを起動するために使用され、同期のように 1 つのスレッドをランダムに起動したり、すべてのスレッドを起動したりするのではなく、正確に起動できます。

28. JMM (Java メモリ モデル) について話す

JDK1.2 より前では、Java のメモリ モデル実装は共有メモリから変数を読み取るため、特別な注意は必要ありません。現在の Java メモリ モデルでは、スレッドは共有メモリで直接読み書きする代わりに、変数をローカル メモリ (マシン レジスタなど) に保存できます。これにより、スレッドが共有メモリ内の変数の値を変更する一方で、別のスレッドがローカル メモリ内の共有変数のコピーを使用し続けるため、データの不整合が発生する可能性があります。

この問題を解決するには、変数を volatile として宣言する必要があります。これにより、この変数は共有され不安定であることが JVM に指示され、使用されるたびに共有メモリに読み取られます。

したがって、volatile キーワードは、JVM 命令の再配置を防ぐだけでなく、変数の可視性を確保する上でも重要な役割を果たします。

詳細: https://blog.csdn.net/m0_55155505/article/details/126134031#JMM_10

29. 揮発性とはどういう意味ですか?

Volatile は Java 仮想マシンによって提供される軽量の同期メカニズムであり、可視性と順序を保証できますが、アトミック性は保証できません。

同時プログラミングの 3 つの重要な特性

  1. 原子性: 操作が中断不可能であり、完全に実行されるか、まったく実行されないかを意味します。
  2. 可視性: 複数のスレッドが同じ変数にアクセスし、1 つのスレッドが変数の値を変更すると、他のスレッドは変更された値をすぐに確認できます。
  3. 順序性: プログラムが実行される順序は、コードが実行される順序で実行されます。

30. volatile をどこで使用しましたか

シングルトンモードで使用されており、本来は両端ロックチェック(ロック前後の判定)のみを使用していましたが、命令の並び替えにより、最初のインスタンス検出時に特定のスレッドがnullにならない場合があります。時間ですが、実際にはインスタンスはまったく初期化されていないため、命令の再配置を禁止するには volatile を使用します

31. 同期型と揮発型の違い

同期キーワードと揮発キーワードは対立するものではなく、補完する存在です!

● volatile キーワードはスレッド同期の軽量実装であるため、volatile のパフォーマンスは synchronized キーワードよりも明らかに優れています。ただし、volatile キーワードは変数にのみ使用でき、synchronized キーワードはメソッドとコード ブロックを変更できます。
● volatile キーワードはデータの可視性を保証できますが、データのアトミック性は保証できません。synchronized キーワードは両方を保証します。
● volatile キーワードは主に複数のスレッド間の変数の可視性を解決するために使用され、synchronized キーワードは複数のスレッド間のリソース アクセスの同期を解決します。

32. 原子性が保証されない問題の解決方法

  • 同期した
  • ロック
  • アトミック整数

33. AtomicInteger を追加すると、原子性が保証されないという問題が解決できるのはなぜですか?

getAndIncrement というメソッドが含まれているため、これは値にアトミックに 1 を加算することを意味します。

このようにして、他のスレッドは、そのスレッドを操作する前に、そのスレッドを操作するスレッドの実行が完了するまで待つ必要があり、最終的にアトミック性が保証されないという問題が解決されます。

AtomicInteger の最下層は CAS です

CAS の正式名は Compare And Swap 「比較と交換」です。これは CPU 同時実行プリミティブです。その機能は、メモリ内の特定の場所の値が期待値であるかどうかを判断し、期待値であれば変更します。それ以外の場合は、メイン メモリとワーキング メモリの値が一致するまで比較が継続され、プロセス全体がアトミックであり、データの不整合が発生することはありません。

例えば:

  1. メイン物理メモリには 5 があり、現時点でそれを操作するスレッドが 2 つあります。
  2. スレッド A と B は両方とも、メイン物理メモリのこの値のコピーを作成します。
  3. スレッド A がメイン物理メモリから値を取得したとき、その値は 5 でした。スレッド A がメイン物理メモリに書き込もうとしたとき、メイン物理メモリの値がまだ 5 であることがわかりました。これは、誰もその値に触れていないことを意味します。この時点で、値は 2019 に正常に変更されました。
  4. 同時に、B スレッドもメイン物理メモリに書き込む必要があり、取り出した値がメイン物理メモリと一致するかどうかを判定すると、メイン物理メモリの値が変更されていることがわかり、 B スレッドはメイン物理メモリの値を変更できません。

34. CASの基本原理

安全でないクラスとスピン

Unsafe は sun.misc パッケージに存在し、CAS のコアクラスです

Java メソッドは基礎となる層に直接アクセスできないため、ネイティブ メソッドを通じてアクセスする必要があります。Unsafe クラスのすべてのメソッドはネイティブに変更され、その内部メソッドは C ポインタのようにメモリを直接操作し、オペレーティング システムの基礎となるリソースを呼び出すことができます。対応するタスクの実行は、Java がオペレーティング システム リソースの中間クラスを直接呼び出すことと同等であるため、Java での CAS の実行は Unsafe クラスのメソッドに依存します。

35. CASのデメリットは何ですか(3)

  1. 長いサイクル タイムと高いオーバーヘッド
    getAndAddInt() メソッドには do while があり、CAS が失敗すると試行を続けます。CAS が長時間失敗すると、CPU に多大なオーバーヘッドが生じます。
  2. 保証できるのは共有変数のアトミック操作のみです。
    共有変数に対して操作を実行する場合、CAS メソッドを使用してアトミック性を保証できますが、複数の共有変数に対して操作を行う場合、循環 CAS は操作のアトミック性を保証できません。現時点では、原子性を確保するためにロックを使用する必要があります。
  3. ABAの問題もあるだろうし

36. ABAの質問

CAS アルゴリズムを実装するための重要な前提条件は、メモリ内の特定の瞬間のデータを取り出し、現在の瞬間と比較して置き換えることです。この時間差によりデータが変更されます。

例:

  • たとえば、スレッド 1 がメモリ位置 V から A を取り出し、このとき、別のスレッド 2 もメモリから A を取り出し、スレッド 2 が値を B に変更する操作を実行します。

  • 次に、スレッド 2 がデータを A に変更します。この時点で、スレッド 1 が CAS 操作を実行すると、メモリにまだ A が存在することがわかり、スレッド 1 は正常に動作します。

  • この間、メモリ内の値が変更されていましたが、最終的には元の値に戻ったため、CASは気付かなかった

ABAをどうやって解決するか?

  • バージョン番号のメカニズムを使用し、変更するときに同時にバージョン番号を比較し、バージョン番号が値と一致する場合は変更し、そうでない場合は変更されません。

37、スレッドローカル

ThreadLocal を使用すると、各スレッドが独自のローカル変数を持つことができます。この変数にアクセスする各スレッドは、この変数のローカル コピーを持つことになります。get() を使用してデフォルト値を取得したり、set() メソッドを使用して値を設定したりできます。現在のスレッド用に保存されたコピーの値により、スレッドの安全性の問題が回避されます。

ThreadLocal 基礎となる
ThreadLocal は、Map と同様の ThreadLocalMap データ構造を内部的に維持します。
ここに画像の説明を挿入

ThreadLocalMap のキーは ThreadLocal オブジェクトで、値は ThreadLocal オブジェクトの set メソッドを呼び出して設定された値です。ThreadLocal に入れる値は、ThreadLocalMap をカプセル化し、変数値を渡しただけです。
ここに画像の説明を挿入

38. ThreadLocal のメモリ リークを理解していますか?

ThreadLocalMap で使用されるキーは ThreadLocal への弱参照ですが、値は強参照です。したがって、ThreadLocal が外部から強く参照されていない場合、キーはガベージ コレクション中にクリーンアップされますが、値はクリーンアップされません。このようにして、キーが null のエントリが ThreadLocalMap に表示されます。何も対策を講じないと、値は GC によって回収されず、このときにメモリ リークが発生する可能性があります。ThreadLocalMap の実装ではこの状況が考慮されており、set()、get()、remove() メソッドが呼び出されると、キーが null のレコードがクリーンアップされます。ThreadLocal メソッドを使用した後、remove() メソッドを手動で呼び出すことをお勧めします。

39. スレッドプールを使用する利点

スレッドの再利用: リソースの消費を削減します。作成されたスレッドを再利用することで、スレッドの作成と破棄のコストを削減します。

同時実行の最大数を制御し、応答速度を向上させます。タスクが到着すると、スレッドの作成を待たずにすぐにタスクを実行できます。

スレッドの管理: スレッドの管理性を向上させます。スレッドは希少なリソースです。無制限に作成すると、システム リソースを消費するだけでなく、システムの安定性も低下します。スレッド プールを使用すると、一元的な割り当て、チューニング、監視が可能になります。

40. RunnableインターフェースとCallableインターフェースの実装の違い

  1. 同時実行性のため、非同期は Callable インターフェイスの出現につながります。
  2. 主な理由は、Callable を使用して、複数のタスクを実行するときに、1 つのタスクに時間がかかる場合に、そのタスクをバックグラウンドで実行できることを実現できるためです。メインスレッドは、最初に他のタスクを完了し、最後にタスクの終了を待ちます。バックグラウンド タスクを実行し、それらをまとめて計算します。

41. スレッドプール

別の記事で要約: https://blog.csdn.net/m0_55155505/article/details/125191350

42. AQSについて理解できましたか?

AQS (AbstractQueuedSynchronizer) の正式名称は、JUC パッケージの下にあるクラスで、ロックとシンクロナイザーを構築するためのフレームワークです。AQS を使用すると、広く使用されている多数のシンクロナイザーを簡単かつ効率的に構築できます。

43. AQSのコンポーネント

セマフォ: セマフォには 2 つの主な機能があり、1 つは複数の共有リソースの相互排他のため、もう 1 つは同時スレッドの数を制御するためのものです。

●acquire(): 取得。スレッドがacquire()操作を呼び出すと、セマフォを正常に取得するか(セマフォから1を引いた値)、スレッドがセマフォを解放するかタイムアウトするまで待機します。
● release(): release。実際にセマフォの値を 1 ずつ増やし、待機中のスレッドをウェイクアップします。

CountDownLatch: スレッドが実行を開始する前にカウントダウンが終了するまで待機できるようにするカウントダウン タイマー。主なメソッドは 2 つあります。

  1. await(): 1 つ以上のスレッドが await() メソッドを呼び出すと、それらのスレッドはブロックされます。
  2. countDown(): 他のスレッドが countDown() メソッドを呼び出すと、カウンターは 1 つ減ります。カウンターの値が 0 になると、await() メソッドによってブロックされていたスレッドが起動され、実行を継続します。 。

CyclicBarrier: その主な機能は、スレッドのグループがバリア (同期ポイントとも呼ばれます) に到達したときにブロックすることです。バリアは、最後のスレッドがバリアに到達するまで開かず、バリアによってブロックされたすべてのスレッドは引き続き動作します。スレッドは、CyclicBarrier.await() メソッドを通じて入力されるバリアです。

おすすめ

転載: blog.csdn.net/m0_55155505/article/details/126937184