是否在线程安全对象上进行同步会阻止可能操纵它的其他调用?

时间:2012-05-11 22:35:25

标签: java concurrency

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

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

如果我同步它:

synchronized (safeQueue) {
   ....
}

阻止代码:

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

3 个答案:

答案 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类在内部同步,因此从外部锁定对象可能会干扰内部锁定。