Freewind @ Thoughtworks scala java javascript dart 工具 编程实践 月结 math python english [comments admin] [feed]

(2011-10-31) 读写锁ReentrantReadWriteLock的疑问

广告: 云梯:翻墙vpn (省10元) 土行孙:科研用户翻墙http proxy (有优惠)

Jdk5中的concurrent包中有一个ReadWriteLock接口以及它的实现(ReentrantReadWriteLock)。通过这个名字,以及它提供的两个方法:

  1. readLock()
  2. writeLock()

可以猜测,它提供了两个锁,一个用来写入,一个用来读取。因为读取不改变数据,可假设读取锁可同时被多个线程持有;而写入锁只能被一个线程持有,因为写入将改变数据。

由于该类的文档写得异常难懂,所以这里用代码来测试。


一、读取锁可同时被多个线程持有

public class ReadLockCanBeHoldByMultiThreadTest {

public static void main(String[] args) {     
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();      
    final ReadLock readLock = lock.readLock();      
    for (int i = 0; i < 3; i++) {      
        new Thread() {      
            public void run() {      
                readLock.lock();      
                System.out.println(Thread.currentThread().getName() + " holds the read lock");      
                try {      
                    Thread.sleep(3000);      
                } catch (InterruptedException e) {      
                    e.printStackTrace();      
                }      
                System.out.println(Thread.currentThread().getName() + " exits");      
            };      
        }.start();      
    }      
}      

}

输出结果如下:

Thread-0 holds the read lock
Thread-2 holds the read lock
Thread-1 holds the read lock
Thread-0 exits
Thread-1 exits
Thread-2 exits

可见读取锁的确可同时被多个线程持有。

二、写入锁不可同时被多个线程持有

public class WriteLockCannotBeHeldByMultiThreads {

public static void main(String[] args) {     
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();      
    final WriteLock writeLock = lock.writeLock();      
    for (int i = 0; i < 3; i++) {      
        new Thread() {      
            public void run() {      
                writeLock.lock();      
                System.out.println(Thread.currentThread().getName() + " holds the read lock");      
                try {      
                    Thread.sleep(3000);      
                } catch (InterruptedException e) {      
                    e.printStackTrace();      
                }      
                writeLock.unlock();      
                System.out.println(Thread.currentThread().getName() + " exits");      
            };      
        }.start();      
    }      
} 

}

结果如下:

Thread-0 holds the read lock
Thread-0 exits
Thread-1 holds the read lock
Thread-1 exits
Thread-2 holds the read lock
Thread-2 exits

可见写入锁必须在释放后,才能被另一个线程拿到。

三、写入锁与读取锁不可同时被不同线程持有

public class ReadWriteLockCannotBeHeldAtTheSameTime {

public static void main(String[] args) throws Exception {     
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();      
    final ReadLock readLock = lock.readLock();      
    final WriteLock writeLock = lock.writeLock(); 

    new Thread() {     
        public void run() {      
            readLock.lock();      
            System.out.println(Thread.currentThread().getName() + " holds the read lock");      
            try {      
                Thread.sleep(3000);      
            } catch (InterruptedException e) {      
                e.printStackTrace();      
            }      
            readLock.unlock();      
            System.out.println(Thread.currentThread().getName() + " released the read lock");      
        };      
    }.start(); 

    // let the first thread have enough time to hold the read lock     
    Thread.sleep(1000); 

    new Thread() {     
        public void run() {      
            writeLock.lock();      
            System.out.println(Thread.currentThread().getName() + " holds the write lock");      
            try {      
                Thread.sleep(3000);      
            } catch (InterruptedException e) {      
                e.printStackTrace();      
            }      
            writeLock.unlock();      
            System.out.println(Thread.currentThread().getName() + " released the write lock");      
        };      
    }.start(); 

}     

}

结果如下:

Thread-0 holds the read lock
Thread-0 released the read lock
Thread-1 holds the write lock
Thread-1 released the write lock

可见读取写被一线程持有后,其它线程必须等它释放后,才能拿到写入锁。反过来也一样,如果写入锁被拿了,读取锁也就拿不到了。

四、某线程拿到写入锁后,还能再拿读取锁

public class AThreadCanHoldWriteAndReadLock {

public static void main(String[] args) {      
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();      
    final ReadLock readLock = lock.readLock();      
    final WriteLock writeLock = lock.writeLock();      
    writeLock.lock();      
    System.out.println("Hold the write lock");      
    readLock.lock();      
    System.out.println("Hold the read lock");      
}      

}

输出:

Hold the write lock
Hold the read lock

五、反过来不行,拿到读取锁后,就拿不到写入锁了

public class AThreadCannotHoldReadAndWriteLock {

public static void main(String[] args) {      
    ReentrantReadWriteLock lock = new ReentrantReadWriteLock();      
    final ReadLock readLock = lock.readLock();      
    final WriteLock writeLock = lock.writeLock();      
    readLock.lock();      
    System.out.println("Hold the read lock");      
    writeLock.lock();      
    System.out.println("Hold the write lock");      
}      

}

输出如下:

Hold the read lock

程序永远卡在这里了,因为拿不到写入锁而陷入等待。

(待续)

comments powered by Disqus