スレッド セーフなオブジェクトを作成するとします。
PriorityBlockingQueue<Object> safeQueue = new PriorityBlockingQueue<Object>();
同期する場合:
synchronized (safeQueue) {
....
}
ブロックするコード:
// some non-synchronized block
Object value = safeQueue.poll();
スレッド セーフなオブジェクトを作成するとします。
PriorityBlockingQueue<Object> safeQueue = new PriorityBlockingQueue<Object>();
同期する場合:
synchronized (safeQueue) {
....
}
ブロックするコード:
// some non-synchronized block
Object value = safeQueue.poll();
いいえ。ブロッキングが発生するのは、別のスレッドも同じsynchronizedオブジェクトに対してa を実行している場合のみです。コードがメソッドである場合、またはコードがコードを使用している場合にのみsynchronized (safeQueue)、への呼び出しがPriorityBlockingQueue.poll()ブロックされます。poll()synchronizedsynchronized (this)
コード を呼び出すとsafeQueue.poll()、実際にはinternal が使用され、. のコードは次のとおりです。PriorityBlockingQueueReentrantLocksynchronized (this)poll()
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return q.poll();
} finally {
lock.unlock();
}
}
最後に、あなたが言及したように、PriorityBlockingQueueすでに再入可能であるため、複数のスレッドがキューにアクセスできるようにするために同期する必要はありません。もちろん、独自のコードで競合状態を解決する必要がある場合は、同期する必要があります。
簡単に言えば、スレッド セーフ クラスのスレッド セーフがどこから来るかによって異なります。
そのルートをたどりたい場合は、クラスのドキュメントまたはその実装コードに依存する必要があります (将来のバージョンでの変更に注意してください...)。 (または同期している他のもの)。
特に、多くのjava.util.concurrentクラスが非ブロックであるため (したがって、スレッド セーフを実現するためにクラス自体を同期しないため)、ブロックする必要はありません。一方、クラスがsynchronized(this)(または同等のsynchronizedインスタンス メソッド) からスレッド セーフを取得する場合、はい、それはブロックされます。この例は、 から返されたマップです。このCollections.synchronizedMapブロックでは、ブロックが文書化されており、実際には意図された機能です (マップをアトミックにクエリおよび変更できるようにするため)。
オブジェクト自体に、インスタンスで同期されるメソッドがある場合は可能です。例えば:
MyClass c = new MyClass();
synchronized(c) {
...
}
とMyClassは:
class MyClass {
// foo needs a lock on this
public synchronized void foo() {
...
}
}
c.foo();これで、セクションの外側への呼び出しは、synchronized上記のコードと並行して実行された場合でもブロックされます。
たとえば、古いJavaVectorクラスはこのように内部で同期されていたため、外部からオブジェクトをロックすると、内部ロックが妨げられる可能性があります。