Javaのロックはインスタンス(オブジェクト)ベースで取得されると読みました(インスタンスメソッドの場合)
また、ロックはクラスのオブジェクトで取得できます(静的メソッドの場合)。
しかし、特定のオブジェクトが一度にいくつのロックを取得できるのだろうか?
オブジェクトは一度に複数のロックを所有できますか?
はいの場合、例を挙げて説明してください。
私のコンセプトを明確にするのを手伝ってください。
Javaのロックはインスタンス(オブジェクト)ベースで取得されると読みました(インスタンスメソッドの場合)
また、ロックはクラスのオブジェクトで取得できます(静的メソッドの場合)。
しかし、特定のオブジェクトが一度にいくつのロックを取得できるのだろうか?
オブジェクトは一度に複数のロックを所有できますか?
はいの場合、例を挙げて説明してください。
私のコンセプトを明確にするのを手伝ってください。
同期ブロックごとに 1 つのオブジェクトのみ。オブジェクトはロックを所有しません。作業するオブジェクトをロックするのは、実行のスレッドです。
ロックは常にオブジェクトで取得されます。たとえば、以下はロックを取得できる 2 つの例です。最初のものは、クラス (オブジェクト) のインスタンスをロックします。
Object obj = new Object();
synchronized(obj) {
workOnIt(obj);
}
2 つ目は、クラスをロックしているように見えます。しかし、Test.class は、私の Test クラスの java.lang.Class インスタンスの特別な表現です。
synchronized(Test.class) {
// call some static method here
}
1 つのスレッドは、複数のオブジェクトに対して複数のロックを保持できます。ただし、リスクを負う必要があります (デッドロックやパフォーマンスの低下を避けるため)。
synchronized (obj1)
{
synchronized (obj2)
{
// do sth. against obj1 and obj2
}
}
静的メソッドを使用してクラスのロックを取得すると、他のオブジェクトと同じようにオブジェクトのロックを取得できます。
class A {
synchronized void foo() {
// do something.
}
static synchronized void bar() {
// do something.
}
}
基本的には
class A {
void foo() {
Object locked = this;
synchronized(locked) {
// do something.
}
}
static void bar() {
Object locked = A.this;
synchronized(locked) {
// do something.
}
}
}
持っているロックの数を混乱させる可能性がある唯一のクラスは、のインスタンスですLock。これは別のスタイルのロックですが、オブジェクトでもあるため、標準のロックもあります。だからあなたはできる
Lock lock = new ReentrantLock();
lock.lock();
lock.unlock();
ただし、混乱する可能性があります
Lock lock = new ReentrantLock();
synchronized(lock) { // don't do this.
lock.wait(); // argh.
}
ロック (同期ブロックまたはメソッドの形式) には、1 つの主要な効果があります。このオブジェクトの同期ブロック/メソッドに同時に入ることができるスレッドは 1 つだけです。つまり、1 つのスレッドだけがこのロックの所有者になることができます (または "モニター"、JLS で呼ばれているように)。
(別の効果は、1 つの同期ブロック内 (または前) で変更されたすべての変数が、同じモニター上の後の同期ブロック内 (または後) にあるときに、他のスレッドで確実に表示されることです。)
このブロックで使用するオブジェクト/変数の数は自由に決定できますが、通常は、何らかの形でまとめられているすべてのデータに対して 1 つのロックを使用し、個別に変更/アクセスしてはなりません。
オブジェクトをロックしても、他のスレッドによるこのオブジェクトの変更/使用が回避されるわけではなく、他のスレッドがこのオブジェクトで同期するのを回避するだけであることに注意してください。そのため、関連するすべてのメソッドを必ず同期してください (パブリック変数は使用しないでください)。
同期ブロックを使用する方法を検討してください ( JVMSから適応)
public void foo(Object f) {
synchronized(f) {
doSomething();
}
}
これを疑似コード(Java とバイトコードの混合!!!) に変換してみましょう。
public void foo(Object f) {
monitorenter(f);
try {
doSomething();
monitorexit(f);
} catch(Throwable e) {
monitorexit(f);
throw e;
}
}
バイトコード命令とJava メソッドの場合は、次のようになります。monitorentermonitorexit
各オブジェクトには 1 つのモニターがあります。1 つのスレッドがモニターに入り、モニターが取得 (ロック、取得) されていない場合は、モニターを取得 (ロック、取得) して呼び出しますdoSomething()(次の行)。
ここで 2 番目のスレッドが来て、 object のモニターに入ろうとすると、 objectのモニターが解放さfれるまでこの場所で待機します。f最初のスレッドが 2 つのmonitorexit命令 (バイトコード!!) のいずれかを呼び出すと、モニターが解放されます。
質問に戻りますが、1 つのスレッドで何台のモニターに入ることができますか? 制限はありません (スタック サイズの制限を除く)。doSomethingが別の同期メソッドであり、 Object のモニターを使用する場合g、スレッド 1 もそのモニターに入り、モニターを取得しgます (利用可能な場合)。
ロックを取得するのはオブジェクトではなく、オブジェクトモニターに入るスレッドであり、そのプロセスは「ロック」しています。