この記事では、java に関する関連知識を提供します。主にスレッド インタビューの質問に関連する問題を整理します。これには、sychronied で変更された通常のメソッドと静的メソッドの違い、CAS ロックフリー プログラミングの原理、違いが含まれます。 volatile と synchronize の間など、一緒に見ていきましょう。皆さんのお役に立てれば幸いです。
推奨学習: 「java ビデオ チュートリアル 」
オブジェクト ロックはオブジェクト インスタンス メソッドまたはオブジェクト インスタンスに使用され、クラス ロックはクラスの静的メソッドまたはクラスのクラス オブジェクトに使用されます。クラスには多数のオブジェクト インスタンスが存在する可能性があることがわかっていますが、各クラスにはクラス オブジェクトが 1 つしかないため、異なるオブジェクト インスタンスのオブジェクト ロックは互いに干渉しませんが、各クラスに存在するクラス ロックは 1 つだけです。
注意しなければならないのは、クラス ロックは概念的なものであり、実際には存在せず、実際には各クラスの対応するクラス オブジェクトをロックすることです。クラス ロックとオブジェクト ロックも相互に干渉しません。
可視性とは、複数のスレッドが同じ変数にアクセスするときに、1 つのスレッドが変数の値を変更すると、他のスレッドが変更された値をすぐに確認できることを意味します。
スレッドによる変数の操作はすべて作業メモリ内で実行する必要があり、メイン メモリ内の変数を直接読み書きすることはできないため、共有変数 V については、最初に独自の作業メモリに配置され、次にメイン メモリに同期されます。メモリ。 。ただし、メインメモリへのフラッシュが間に合わず、ある程度の時間差が生じます。明らかに、この時点では、変数 V に対するスレッド A の操作はスレッド B からは認識されなくなります。
共有オブジェクトの可視性の問題を解決するには、volatile キーワードまたはロックを使用できます。
現在のプロセッサは基本的に CAS() 命令をサポートしていますが、メーカーごとに実装されているアルゴリズムが異なり、各 CAS 演算プロセスにはメモリアドレス V、期待値 A、新しい値 B の 3 つの演算子が含まれています。このアドレスに格納されている値が期待値 A と等しい場合、そのアドレスの値は新しい値 B に割り当てられます。それ以外の場合、操作は実行されません。
CAS の基本的な考え方は、このアドレスの値が期待値と等しい場合は新しい値を与え、それ以外の場合は何もせずに元の値を返すというものです。ループ CAS は、cas 操作を成功するまでループで実行し続けることです。 CAS に関する 3 つの主要な問題についてもお話します。
スレッドは、すでに所有しているロックと同期している任意のコード ブロックに繰り返し入ることができます。Synchronized ロックと ReentrantLock は両方とも再入可能なロックです。実装面では、スレッドがロックを取得するたびに、ロックを取得しているスレッドが自分自身であるかどうかを判断し、単純にカウンタを累積します。ロックが解放されるたびに、計算機がゼロに戻るまでカウンタはデクリメントされます。スレッドが完全に解放されました。ロックします。最下層は JUC の AQS を使用して実装されます。
これは、ロックやその他の同期コンポーネントを構築するために使用される基本的なフレームワークです。たとえば、ReentrantLock、ReentrantReadWriteLock、CountDownLatch は AQS に基づいて実装されます。 int メンバー変数を使用して同期ステータスを表し、組み込み FIFO キューを使用してリソース取得スレッドのキューイング作業を完了します。これは、CLH キュー ロックの変形実装です。排他的と共有の 2 つの同期方法を実現できます。
AQS を使用する主な方法は継承です。サブクラスは AQS を継承し、その抽象メソッドを実装して同期ステータスを管理します。シンクロナイザーの設計はテンプレート メソッド パターンに基づいているため、独自の同期ツール クラスを実装する場合は、 tryAcquire、tryReleaseShared などのいくつかのオーバーライド可能なメソッド。
この設計の目的は、同期コンポーネント (ロックなど) がユーザー指向であることです。これは、ユーザーが同期コンポーネントと対話するためのインターフェースを定義し (たとえば、2 つのスレッドが並行してアクセスできるようにします)、実装を非表示にします。詳細; シンクロナイザはユーザー指向です。ロックの実装者です。ロックの実装を簡素化し、同期状態管理、スレッドのキューイング、待機およびウェイクアップなどの基礎となる操作をシールドします。これにより、ユーザーと実装者が注力する必要がある領域が効果的に分離されます。
内部的には、AQS は共有リソースの状態を維持し、組み込み FIFO を使用してリソース取得スレッドのキューイング作業を完了します。キューは 1 つずつ Node ノードで構成され、各 Node ノードは、それぞれ自身の先行ノードと後続ノードを指す前参照と次参照を保持し、両端の二重リンク リストを形成します。
同期 (この) 原則: 2 つの命令:monitorenter、monitorexit が含まれます; 同期メソッドについて話しましょう。同期メソッドの逆コンパイル結果から判断すると、メソッドの同期は、monitorenter およびmonitorexit 命令を通じては達成されません。通常のメソッドと比較して、定数プールに追加の ACC_SYNCHRONIZED 識別子があります。
JVM は、この識別子に基づいてメソッド同期を実装します。メソッドが呼び出されるとき、呼び出し命令は、メソッドの ACC_SYNCHRONIZED アクセス フラグが設定されているかどうかを確認します。設定されている場合、実行スレッドは最初にモニターを取得します。取得が成功すると、メソッド本体を実行でき、メソッド実行後にモニターを解放できます。メソッドの実行中、他のスレッドは同じモニター オブジェクトを再度取得できません。
スピン ロック、適応スピン ロック、ロック除去、ロック粗密化、バイアス ロック、軽量ロック、エスケープ解析などのテクノロジーの導入、およびその他の削減のためのテクノロジーロック操作のコスト。
オブジェクト ロックは、オブジェクト インスタンス メソッドまたはオブジェクト インスタンスに使用され、クラス ロックは、クラスの静的メソッドまたはクラスのクラス オブジェクトに使用されます。クラスには多数のオブジェクト インスタンスが存在する可能性があることがわかっていますが、各クラスにはクラス オブジェクトが 1 つしかないため、異なるオブジェクト インスタンスのオブジェクト ロックは互いに干渉しませんが、各クラスに存在するクラス ロックは 1 つだけです。
注意しなければならないのは、クラス ロックは概念的なものであり、実際には存在せず、実際には各クラスの対応するクラス オブジェクトをロックすることです。クラス ロックとオブジェクト ロックも相互に干渉しません。
DCL の役割が次であるという保証はありません。 volatile は変更された変数の可視性と順序を保証し、シングルトン モードではオブジェクト作成時の実行順序が
であることを保証します。 Volatile は最も軽量な同期メカニズムです。 Volatile は、さまざまなスレッドがこの変数を操作するときの可視性を保証します。つまり、1 つのスレッドが変数の値を変更すると、新しい値は他のスレッドからすぐに可視になります。ただし、volatile は操作のアトミック性を保証できないため、マルチスレッドでの複合書き込み操作ではスレッドの安全性の問題が発生します。
キーワード synchronized は、メソッドまたは同期ブロックの形式を変更するために使用できます。これは主に、複数のスレッドがメソッドまたは同期ブロック内で同時に 1 つのスレッドのみを持つことができることを保証します。これにより、スレッドが変数に安全にアクセスできるようになります。可視性と排他性。組み込みロック機構とも呼ばれます。
デーモン スレッドは、主にプログラムのバックグラウンド スケジューリングとサポート作業に使用されるため、サポート スレッドです。これは、Java 仮想マシンに非デーモン スレッドが存在しない場合、Java 仮想マシンは終了することを意味します。 Thread.setDaemon(true) を呼び出すことで、スレッドをデーモン スレッドとして設定できます。通常は使用しませんが、たとえば、ガベージ コレクション スレッドはデーモン スレッドです。
スレッド中止: 実行の実行が完了するか、ハンドルされない例外がスローされ、スレッドが早期に終了します。操作の一時停止、再開、停止を行うスレッド Thread に対応する API は、suspend()、resume()、stop() です。ただし、これらの API は古いため、使用はお勧めできません。プログラムが不確実な状態で動作することになるからです。
安全な一時停止とは、他のスレッドが、interrupt() メソッドを呼び出して、特定のスレッド A に割り込むことです。割り込まれたスレッドは、スレッド メソッド isInterrupted() によって割り込まれたかどうか、または静的メソッド Thread.interrupted を呼び出すことができるかどうかを判断します。 () は現在のスレッドが割り込まれているかどうかを判断するために使用されますが、Thread.interrupted() は割り込みフラグ ビットも false に書き換えます。
yield() メソッド: 現在のスレッドに CPU 所有権を放棄させますが、放棄する時間を設定することはできません。ロックリソースは解放されません。 yield() を実行するすべてのスレッドは、オペレーティング システムによって再度選択され、準備完了状態に入った直後に実行される場合があります。
yield() と sleep() が呼び出された後、現在のスレッドによって保持されているロックは解放されません。
wait() メソッドを呼び出した後、現在のスレッドが保持しているロックが解放され、現在のスレッドが起動された後、再度ロックを競合します。wait メソッドの背後にあるコードは、待機メソッドの呼び出し後にのみ実行されます。ロックが競合します。
Wait は通常、スレッド間の対話に使用され、sleep は通常、実行の一時停止に使用され、yield() メソッドにより現在のスレッドに CPU 所有権を放棄させます。
待機スレッドは、notify/notifyAll() を使用してウェイクアップします。
スリープ中にスレッドが中断されると、割り込み例外がスローされます。
Java のスレッドのステータスは 6 つのタイプに分類されます。
ThreadLocal は Java の特別な変数です。 ThreadLocal は各スレッドに変数のコピーを提供するため、各スレッドが特定の時点で同じオブジェクトにアクセスすることがなくなり、複数のスレッドによるデータの共有が分離されます。
内部実装に関しては、各スレッドには内部に ThreadLocalMap があり、各スレッドが所有する変数のコピーを保存するために使用されます。
開発プロセス中、スレッド プールを合理的に使用すると 3 つのメリットが得られます。
まず: リソース消費を削減します。
2 番目: 応答速度の向上。
3 番目: スレッドの管理性を向上させます。
join メソッドを使用して実装できます。
推奨学習: 「Java ビデオ チュートリアル 」
以上がJava スレッドのインタビューの質問を要約して整理するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。