3

假设我创建了一个线程安全对象:

PriorityBlockingQueue<Object> safeQueue = new PriorityBlockingQueue<Object>();

如果我同步它:

synchronized (safeQueue) {
   ....
}

是否会阻止代码:

// some non-synchronized block
Object value = safeQueue.poll();
4

3 回答 3

4

不。唯一一次你得到任何阻塞是如果另一个线程也在synchronized同一个对象上执行。如果您的代码是synchronized (safeQueue),那么只有在是方法或代码使用代码时PriorityBlockingQueue.poll()才会阻塞。poll()synchronizedsynchronized (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它已经是可重入的,因此您不需要对其进行同步以允许多个线程访问队列。当然,如果您需要在自己的代码中解决竞争条件,您仍然可能需要对其进行同步。

于 2012-05-11T22:36:22.390 回答
2

简短的回答是:这取决于线程安全类的线程安全性来自何处。

如果你想走这条路(小心未来版本的变化......),你必须依赖类的文档或它的实现代码,或者是防御性的而不是信任它,而是在另一个对象上同步以满足你的原子性需求(或您正在同步的任何其他内容)。

它当然不必阻塞,特别是因为许多java.util.concurrent类都是非阻塞的(因此不会自行同步以实现线程安全)。另一方面,如果该类从synchronized(this)(或等效地,synchronized实例方法)获得其线程安全性,那么是的,这将阻塞。这方面的一个示例是从 返回的地图Collections.synchronizedMap,其中记录了阻塞并且实际上是预期的功能(以便您可以原子地查询和修改地图)。

于 2012-05-11T23:28:37.740 回答
0

如果对象本身具有在实例上同步的方法,这是可能的。例如:

MyClass c = new MyClass();
synchronized(c) {
    ...
}

并且MyClass是:

class MyClass {

    // foo needs a lock on this
    public synchronized void foo() { 
       ...
    }
}

现在,如果与上面编写的代码并行执行,对节c.foo();外部的调用仍然会阻塞。synchronized

例如,旧的 JavaVector类是这样在内部同步的,因此从外部锁定对象可能会干扰内部锁定。

于 2012-05-11T22:43:52.380 回答