ReentrantReadWriteLock和synchronized块

时间:2014-04-23 21:01:13

标签: java multithreading synchronization locking

如果我有一个ReentrantReadWriteLock,并且我将它用作同步块中的锁,那么其他线程是否仍然可以释放它们的锁?

例如:

ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);

public void doSomething() {
    synchronized(lock) {
        lock.readLock().lock();
        // do stuff
        lock.readLock().unlock();
    }
}

如果我调用doSomething()并且另一个线程已经持有读锁定,该线程是否可以释放读锁定?

当我进行doSomething()调用时,我将在ReentrantReadWriteLock上进行同步,然后尝试获取读锁定。由于某些东西已经持有读锁定,因此我将阻止该锁定被释放。我很想知道读锁是否可以被释放,因为我已经锁定了锁本身。

2 个答案:

答案 0 :(得分:1)

在ReentrantReadWriteLock对象上进行同步似乎是一个非常糟糕的主意。您的示例是锁定两个完全独立的锁。首先,它将内置的互斥锁锁定到每个对象(在本例中为ReentrantReadWriteLock对象),然后锁定读锁。

任何时候你看到一个锁,你应该问这个问题,"锁应该保护的不变量是什么?"这是另一种询问方式,"如果锁定不存在,您的数据会以何种方式被破坏?"

好的,synchronized(lock)保护什么?

而且,lock.readLock().lock()保护了什么?

如果两个答案都相同,那么为什么要使用两个锁?

  

如果由我决定,我甚至不会首先包含读/写锁

你也可以改变你的例子:

Object lock = new Object();

public void doSomething() {
    synchronized(lock) {
        // do stuff
}

就你向我们展示的代码而言,它不会有任何不同的行为。 (但是,它可能会改变您的示例与您尚未向我们展示的其他代码进行交互的方式。)

答案 1 :(得分:0)

编写一个示例,显示一个在实际锁定对象上保存监视器的线程不会阻碍其他线程获取和释放读取锁定,这是非常简单的。 (这当然没有实际记录,因此理论上对于替代Java实现可能会有所不同!)

public static void main(String[] args) throws Exception {
    final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true);

    synchronized (lock) {
        lock.readLock().lock();
        try {
            for (int i = 0; i < 10; i++) {
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        lock.readLock().lock();
                        try {
                            System.out.println("foo");
                        } finally {
                            lock.readLock().unlock();
                        }
                    }
                }).start();
            }
            Thread.sleep(500);
            System.out.println("done");
        } finally {
            lock.readLock().unlock();
        }
    }
}