同期メソッドと同期ブロックの違いは知っていますが、同期ブロックの部分についてはわかりません。
私はこのコードを持っていると仮定します
class Test {
private int x=0;
private Object lockObject = new Object();
public void incBlock() {
synchronized(lockObject) {
x++;
}
System.out.println("x="+x);
}
public void incThis() { // same as synchronized method
synchronized(this) {
x++;
}
System.out.println("x="+x);
}
}
この場合、lockObjectを使用することとthisをロックとして使用することの違いは何ですか?私と同じように思えます。
同期ブロックを使用することにした場合、どのオブジェクトをロックするかをどのように決定しますか?
個人的には、「これ」をロックすることはほとんどありません。私は通常、他のコードがロックオンしないことを知っている私有参照をロックします。 「this」をロックすると、anyオブジェクトについて知っている他のコードがロックを選択する場合があります。発生する可能性は低いですが、確かに発生する可能性があり、デッドロック、または過度のロックを引き起こす可能性があります。
あなたがロックするものについて特に魔法のようなものはありません-あなたはそれをトークンとして効果的に考えることができます。同じトークンでロックしている人は誰でも同じロックを取得しようとしています。 want同じロックを取得できる他のコードでない限り、プライベート変数を使用します。 also変数final
を作成することをお勧めします-私がeverロック変数をオブジェクトの寿命。
Java Concurrency In Practiceを読んでいたときにこの同じ質問がありました。JonSkeetとspullaraによって提供された回答について、さらに視点を追加すると思いました。
setValue(int)
メソッドの実行中に「クイック」getValue()
/doStuff(ValueHolder)
メソッドもブロックするコードの例を次に示します。
public class ValueHolder {
private int value = 0;
public synchronized void setValue(int v) {
// Or could use a sychronized(this) block...
this.value = 0;
}
public synchronized int getValue() {
return this.value;
}
}
public class MaliciousClass {
public void doStuff(ValueHolder holder) {
synchronized(holder) {
// Do something "expensive" so setter/getter calls are blocked
}
}
}
同期にthis
を使用することの欠点は、クラスへの参照で他のクラスが同期できることです(もちろんthis
経由ではありません)。オブジェクト参照のロック中にsynchronized
キーワードを悪意のあるまたは意図しない使用すると、外部クラスがthis
同期メソッドを効果的にブロックする可能性があるため、同時使用ではクラスの動作が低下する可能性があります。 (クラスで)実行時にこれを禁止することはできません。この潜在的な落とし穴を回避するには、private final Object
で同期するか、Java.util.concurrent.locks
でLock
インターフェイスを使用します。
この簡単な例では、セッター/ゲッターを同期する代わりに、AtomicInteger
を代わりに使用できます。
Effective Java Second Edition Item 67.
Javaのすべてのオブジェクトはモニターとして機能できます。1つを選択することは、必要な粒度に依存します。「これ」を選択すると、他のクラスも同じモニターで同期できるという利点と欠点があります。ただし、synchronizeキーワードを直接使用することは避け、代わりに、より高いレベルでセマンティクスが明確に定義されたJava.util.concurrencyライブラリの構成体を使用することをお勧めします。
Java並行性の実践 http://amzn.com/0321349601
この場合、どのオブジェクトをロック用に選択してもかまいません。ただし、正しい同期を実現するには、常に同じオブジェクトをロックに使用する必要があります。上記のコードでは、「this」オブジェクトをロックとして使用し、次に「lockObject」をロックとして使用すると、適切な同期が保証されません。