ユーザーごとに 1 つのリクエストのみがコード ブロックを入力できるように、複数の API リクエストにわたってオブジェクトをロックしたいと考えています。
オブジェクトの参照またはその機能synchronized(obj)
に基づいてロックしますか?hashCode()
つまり、私はすることができます:
synchronized("asdf") {
doSomethingNifty();
}
ここで、「asdf」には一意のハッシュがありますが、一意の参照はありません。
ユーザーごとに 1 つのリクエストのみがコード ブロックを入力できるように、複数の API リクエストにわたってオブジェクトをロックしたいと考えています。
オブジェクトの参照またはその機能synchronized(obj)
に基づいてロックしますか?hashCode()
つまり、私はすることができます:
synchronized("asdf") {
doSomethingNifty();
}
ここで、「asdf」には一意のハッシュがありますが、一意の参照はありません。
synchronized(obj) は、オブジェクトのメモリ位置またはその toHash() 関数に基づいてロックしますか?
ない。オブジェクトに関連付けられたモニターをロックしています。JVM に関しては、オブジェクトのメモリ アドレスについては説明しません。それは再配置可能であり、Object.hashcode()
一意ではないため、ハッシュ コードではないからです ( の観点からも)。
何をロックするかという点では、同じfinal
オブジェクトである必要があります。何かのようなもの:
private final Object lockObject = new Object();
...
synchronized (lockObject) {
// do stuff that needed to be protected
}
final
複数のスレッドが、変更されていない同じオブジェクト参照をロックしていることを保証できるようにする必要があります 。private
良いので、クラス外がクラス内のロックを台無しにすることはありません。
ここで、「asdf」には一意のハッシュがありますが、一意のメモリ アドレスはありません。
"asdf"
他の文字列が同じハッシュを持つ可能性があり、コンパイラがJava 文字列プールに格納する場合、アプリケーションでの "asdf" のすべての使用にわたって実際には一意の "メモリ アドレス" を持つ可能性があるため、一意のハッシュはありません。つまり、まったく異なるクラスにも同じ悪いパターン コード ブロックが含まれている可能性があり、同じオブジェクト インスタンスをロックしているため、クラスの同期に影響を与える可能性があります。そのため、ロック オブジェクトは非常に重要です。String
private
Boolean
この件について話している間、またはのような非最終オブジェクトのような可変値で同期してはいけませんInteger
。次のパターンはよく使用されますが、非常に間違っています。
Boolean value = false;
...
// really bad idea
synchronized (value) {
if (value) {
value = false;
} else {
value = true;
}
}
参照が変更されているため、これは非常に間違っています。value
そのため、1 つのスレッドがそれをロックしてからその参照値を変更し、別のスレッドが別のオブジェクトをロックし、両方のスレッドがsynchronized
同時にそのオブジェクト内にある可能性があります。さらに悪いことに、aには定数であるandBoolean
の値が 2 つしかないため、複数のクラスが同じ参照をロックすることになります。true
false
オブジェクトを介して同期しています。メモリアドレスの問題は純粋に実装の問題であり、あなたには関係ありません。同じオブジェクト (つまり、まったく同じインスタンス) である限り、同期は行われます。
別のインスタンスを使用すると、同期は機能しません。あなたができることは、 public static 定数を lock として定義することです:
public final static Object LOCK = new Object();
そしてそれを使う
synchronized(SomeClass.LOCK) {
ロックはオブジェクト自体のインスタンスにあり、そのように考えたい場合は、メモリの場所と考えることができます。したがって、あなたが提案していることはうまくいきません。
代わりに、保護したいコードのブロックに対応する単一のオブジェクトが必要なように思えます。したがって、プログラムのセットアッププロセスのどこかで、次のようなものが必要です
static Object lockObject = new Object();
そして、あなたはすることができます
synchronized(lockObject) {
doSomethingNifty();
}
ただし、doSomethingNifty() が特定のオブジェクトに関連している場合は、lockObject の代わりにそのオブジェクトを使用することが非常に理にかなっています。また、doSomethingNifty() の実行が高速であることを確認してください。そうしないと、多くのユーザーが待たされることになります。