この記事では主に、同期のさまざまな使用法とロック解除の基本的な原則について説明します。
1. ヘビーウェイトロック
オブジェクトヘッダー
重量ロックについて話す前に、まずオブジェクトの構成を理解しましょう。オブジェクトは、オブジェクト ヘッダーとオブジェクト本体で構成されます。この記事では主にオブジェクト ヘッダーについて説明します。オブジェクト本体は、実際にはオブジェクトのメンバー変数です。オブジェクトのヘッダーはマーク ワードとクラス ワードで構成されます。クラス ワードは現在のオブジェクトのタイプを指し、マーク ワードは通常の状態のオブジェクトのハッシュコード、その時代、偏っているかどうかを指します。ロック、およびロック状態については、次の図を参照してください。
モニター (ロック) - オペレーティング システムの基礎となる実装であり、弊社によって直接制御されません。
次に、本格的にヘビーウェイトロックの説明に入りますが、まず、各 Java オブジェクトをモニター オブジェクトに関連付けることができます。synchronized を使用する限り、オブジェクトのマークワークはモニターのポインター アドレスを変更するように設定されます。ステータスは 10 に設定されます (上記を参照)。
全体の手順は次のとおりです。
- まず、モニター オブジェクトは最初はどのオブジェクトにもバインドされていませんが、同期されたコード ブロックが初めて実行されるとき、そのオブジェクトは基になるモニター オブジェクトにバインドされ、モニター オブジェクトのポインター アドレスはオブジェクト自体のマークワードに置き換えられます。
- 監視オブジェクトの所有者を現在のスレッドのスタック フレームに設定します。
- 2 番目のスレッドが同期されたコード ブロックに入ると、まず現在のオブジェクトのマークワードがモニターを指しているかどうかを判断します。そうでない場合は、最初の 2 つの手順を実行します。それ以外の場合は、所有者が特定のスレッドを指しているかどうかを判断します。そうである場合は、モニターのエントリリスト。ブロッキングを開始し、所有者が実行を完了するまで待ちます。そうでない場合は、手順 1 と 2 を実行します。
- ロックを解放するときは、まず現在のオブジェクトの参照アドレスを検索し、次にマークワード内のモニター オブジェクト アドレスを取得します。次に、所有者によってポイントされている現在のスレッドをモニターからクリアして、通常の状態のマークワードを取得します。モニターからオブジェクトを取得して通常の状態をリセットして復元し、エントリリスト内のすべてのスレッドをウェイクアップして時間を取得し、スライスごとに上記の手順を繰り返します。
- 同期されたコード ブロックで例外が発生しても心配する必要はありません。これは、現在のオブジェクトの状態をリセットしてエントリリスト内のスレッドを起動し、デッドロックを回避するために例外をスローするのにも役立ちます。
2.軽量ロック
軽量ロックは、重量ロックの置き換えには使用されません。モニターがオペレーティング システムによって提供されるオブジェクトであることはわかっています。ロックを解除するための頻繁な操作は、実際には非常にパフォーマンスを消費する操作です。スレッドの競合がそれほど頻繁ではないとき、いつ、たとえば、前のスレッドがコード ブロックを実行し、次のスレッドが入ると、ロックする必要がなくなります。競合が頻繁に発生する場合は、重量ロックにアップグレードします。
具体的な手順は次のとおりです。
- まず、同期されたコード ブロックが実行されると、ロック レコードが現在のスレッド スタックに書き込まれ、次に現在のオブジェクトの参照アドレスがロック レコードのオブジェクト参照に書き込まれます。
- cas を介して現在のオブジェクトのマークワードとロック レコードのアドレスを交換します。ステータスを 00 に切り替えることは軽量ロックです。図 1 の 3 行目を参照してください。現在のオブジェクトのステータスが 01 であれば、交換は成功します。 , 現在のオブジェクトが現在のスレッドから変更されていることを示します スレッドがそれを保持しています. 00 の場合は交換が失敗し, 以前のロックがすでに他の人によって保持されていることを示します. このとき、次の 2 つの状況に分けられます:
- 最初のスレッドが再び入ります。これは、現在のスレッドがロックを保持していることを意味します。その後、同期されたコード ブロックが再度実行されるため、別のスタック フレーム ロック レコードが左側のスタックに書き込まれますが、置換が失敗したため、アドレスはロック レコードのロック レコードの数は null です。現在のスレッド ロックの数は 1 つ増加します。現在のスレッドはロックを取得しているため、引き続き実行のためにコード ブロックに入ることができます。内部同期されたコード ブロックが実行されると、現在のスレッド ロックの数は実行がその層のコードブロックの中で最も外側に達すると、ロックレコードに値がある場合は最後の層であると判断し、現在の層のロック数が1つ減ります。スレッドが判定され、0の場合はロックが解除され、0の場合はロックが解除されます。
- 2 つ目は、ロックが現在のスレッドによって取得されない場合、ロックは重みロック (または技術的にはロック拡張と呼ばれます) にアップグレードされ、オブジェクトのマークワードがロック レコード アドレスからアドレスに置き換えられます。モニター オブジェクトの値を取得し、モニターの所有者に前のスレッドのスタック アドレスをポイントし、現在のスレッドをエントリ リストに入れてブロックして待機します。