假设我创建了一个线程安全对象:
PriorityBlockingQueue<Object> safeQueue = new PriorityBlockingQueue<Object>();
如果我同步它:
synchronized (safeQueue) {
....
}
阻止代码:
// some non-synchronized block
Object value = safeQueue.poll();
答案 0 :(得分:4)
没有。只有当另一个线程 在同一个对象上执行synchronized
时,才会任何阻塞。如果您的代码为synchronized (safeQueue)
,那么对PriorityBlockingQueue.poll()
的调用只会在poll()
为synchronized
方法或代码使用synchronized (this)
代码时阻止。
当您致电safeQueue.poll()
时,PriorityBlockingQueue
代码实际上使用的是内部ReentrantLock
,而不是正在执行synchronized (this)
。这是poll()
的代码:
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return q.poll();
} finally {
lock.unlock();
}
}
最后,正如您所提到的,PriorityBlockingQueue
已经是可重入的,因此您无需在其上进行同步以允许多个线程访问队列。如果您需要在自己的代码中解决竞争条件,您仍然需要对其进行同步。
答案 1 :(得分:2)
简短的回答是:它取决于线程安全类的线程安全性来自何处。
如果你想沿着那条路走下去(谨防未来版本中的变化......),或者保持防御而不信任它,你必须依赖于类的文档或其实现代码,而是在另一个对象上同步你的原子性需求(或者你正在同步的其他任何东西)。
它当然不必阻塞,特别是因为许多java.util.concurrent
类是非阻塞的(因此不会自身同步以实现线程安全)。另一方面,如果类从synchronized(this)
(或等效地,synchronized
实例方法)获得其线程安全性,那么是,那将阻止。这方面的一个示例是从Collections.synchronizedMap
返回的映射,其中记录了阻塞并且实际上是预期的功能(以便您可以自动查询和修改映射)。
答案 2 :(得分:0)
如果对象本身具有在实例上同步的方法,则可能。例如:
MyClass c = new MyClass();
synchronized(c) {
...
}
和MyClass
是:
class MyClass {
// foo needs a lock on this
public synchronized void foo() {
...
}
}
现在,c.foo();
部分之外的synchronized
调用仍将阻止,如果它与上面编写的代码并行执行。
例如,旧的Java Vector
类在内部同步,因此从外部锁定对象可能会干扰内部锁定。