クラスに 4 つのメソッド ( m1
、m2
、m3
およびm4
) があります。メソッドm1
、m2
およびメソッドm3
ですsynchronized
。t1
また、それぞれ、t2
、t3
および4 つのスレッドがありt4
ます。
メソッド (同期メソッド) にt1
アクセスする場合、アクセスメソッド (同期メソッド) を同時にスレッド化できますか? そうでない場合、t2 の状態はどうなるでしょうか?m1
t2
m2
クラスに 4 つのメソッド ( m1
、m2
、m3
およびm4
) があります。メソッドm1
、m2
およびメソッドm3
ですsynchronized
。t1
また、それぞれ、t2
、t3
および4 つのスレッドがありt4
ます。
メソッド (同期メソッド) にt1
アクセスする場合、アクセスメソッド (同期メソッド) を同時にスレッド化できますか? そうでない場合、t2 の状態はどうなるでしょうか?m1
t2
m2
t1 が m1 メソッド (同期メソッド) にアクセスする場合、t2 スレッドは m2 メソッド (同期メソッド) に同時にアクセスできますか?
synchronized
キーワードはオブジェクト レベルで適用され、オブジェクトのロックを保持できるスレッドは 1 つだけです。したがって、同じオブジェクトについて話している限り、noは、入ったときに取得したロックを解放するのt2
を待ちます。t1
m1
ただし、スレッドは を呼び出すことにより、メソッドから戻らずにロックを解放できますObject.wait()
。
そうでない場合、 t2 の状態はどうなりますか?
じっと座ってt1
、ロックが解放されるのを待ちます (メソッドから戻るか、または呼び出しObject.wait()
ます)。具体的にはBLOCKED
状態になります。
モニター・ロックを待ってブロックされたスレッドのスレッド状態。ブロック状態のスレッドは、監視ロックが同期ブロック/メソッドに入るのを待っているか、 を呼び出した後に同期ブロック/メソッドに再び入るのを待っています
Object.wait
。
サンプルコード:
public class Test {
public synchronized void m1() {
try { Thread.sleep(2000); }
catch (InterruptedException ie) {}
}
public synchronized void m2() {
try { Thread.sleep(2000); }
catch (InterruptedException ie) {}
}
public static void main(String[] args) throws InterruptedException {
final Test t = new Test();
Thread t1 = new Thread() { public void run() { t.m1(); } };
Thread t2 = new Thread() { public void run() { t.m2(); } };
t1.start();
Thread.sleep(500);
t2.start();
Thread.sleep(500);
System.out.println(t2.getState());
}
}
出力:
BLOCKED
メソッドが同じモニターで同期されている場合、異なるスレッドで同時に実行することはできません。2番目のスレッドがモニターエントリ(この場合は同期メソッドの開始)に到達すると、最初のスレッドがモニターを解放するまでブロックされます。
この場合のブロックされたスレッドの実際の状態は、jconsoleによって報告されるように、次のようになります。java.lang.Thread.State: WAITING (on object monitor)
すべてのメソッドが通常のインスタンスメソッドであると仮定すると、同じオブジェクトで呼び出されたときに同じモニターを共有します。つまり、次のようなものがある場合:
// Thread 1
A a1 = new A();
a1.m1();
// Thread 2
A a2 = new A();
a2.m2()
この場合、2番目のスレッドはメソッドを呼び出すことができます。これは、スレッド1によってロックされていないa2
オブジェクトの暗黙的なモニターを取得しようとしているためです。ただし、スレッド2がを呼び出そうとすると、スレッドまでブロックされます。 1は実行を終了しました。a1.m2()
m1()
静的メソッドがある場合、それらはクラス自体の明示的なモニターを取得するため(私の仮想的な名前付けの場合)、インスタンスメソッドの呼び出しA.class
によってブロックされることはありません。
いいえ、できませんでした。それが唯一のポイントですsynchronized
:異なるスレッドはこれらのことを同時に行うことはできません(単一のスレッドは何も並行して行うことができないため、同じスレッドが同時にそれらを行うことを防ぐ必要はありません)。待機中のスレッドのは「ロックを待機中」です。(十分に最新のJVMを使用すると、正しい方法で要求すれば、実際にこの状態をコンソールに表示できます。)
t1 が m1 メソッド (同期メソッド) にアクセスする場合、t2 スレッドは m2 メソッド (同期メソッド) に同時にアクセスできますか?
いいえ。スレッド t2 は、スレッド t1 がロックを解放するのを待ちます。同じ例では、t2 は同期されていないメソッド m4 にアクセスできます。
同期された メソッドのロック
すべてのオブジェクトには固有のロックが関連付けられています。慣例により、オブジェクトのフィールドへの排他的かつ一貫したアクセスを必要とするスレッドは、オブジェクトにアクセスする前にオブジェクトの固有ロックを取得し、それらの操作が完了したら固有ロックを解放する必要があります。
スレッドが同期メソッドを呼び出すと、そのメソッドのオブジェクトの固有ロックが自動的に取得され、メソッドが戻るときに解放されます。キャッチされていない例外が原因で返された場合でも、ロックの解放が発生します。
2 番目のクエリに戻ります。
そうでない場合、 t2 の状態はどうなりますか?
スレッド t2 はブロック状態にあり、スレッド t1 がロックを解放するのを待っています。
Javaドキュメント ページから:
作り方synchronized
には2つの効果があります。
まず、同じオブジェクトに対する同期メソッドの 2 つの呼び出しをインターリーブすることはできません。1 つのスレッドがオブジェクトの同期メソッドを実行している場合、同じオブジェクトの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトの処理を完了するまでブロック (実行を中断) します。
次に、同期メソッドが終了すると、同じオブジェクトに対する同期メソッドの後続の呼び出しとの先行発生関係が自動的に確立されます。これにより、オブジェクトの状態の変更がすべてのスレッドに表示されることが保証されます