介绍
DK1.5之后,提供了读写锁ReentrantReadWriteLock,读写锁维护了一对锁:一个读锁,一个写锁。通过分离读锁和写锁,使得并发性相比一般的排他锁有了很大提升。在读多写少的情况下,读写锁能够提供比排他锁更好的并发性和吞吐量。
源码定义
/* *This lock supports a maximum of 65535 recursive write locks * and 65535 read locks. Attempts to exceed these limits result in * {@link Error} throws from locking methods. * * @since 1.5 * @author Doug Lea */public class ReentrantReadWriteLock implements ReadWriteLock, java.io.Serializable { private static final long serialVersionUID = -6992448646407690164L; /** Inner class providing readlock */ private final ReentrantReadWriteLock.ReadLock readerLock; /** Inner class providing writelock */ private final ReentrantReadWriteLock.WriteLock writerLock; /** Performs all synchronization mechanics */ final Sync sync; ...}
code
public class ReentrantReadWriteLockTest { ReentrantReadWriteLock lock; private ReentrantReadWriteLock.ReadLock readLock; private ReentrantReadWriteLock.WriteLock writeLock; private ReentrantReadWriteLockTest() { lock = new ReentrantReadWriteLock(); readLock = lock.readLock(); writeLock = lock.writeLock(); } public void read() { try { readLock.lock(); System.out.println(Thread.currentThread().getName() + " 开始读了。。。"); Thread.sleep(3000); }catch (InterruptedException e) { }finally { System.out.println(Thread.currentThread().getName() + " 读结束了。。。"); readLock.unlock(); } } public void write() { try { writeLock.lock(); System.out.println(Thread.currentThread().getName() + " 开始写了。。。"); Thread.sleep(3000); } catch (InterruptedException e) { } finally { System.out.println(Thread.currentThread().getName() + " 写完了。。。"); writeLock.unlock(); } }}
测试1
public static void main(String[] args) { final ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest(); Thread t1 = new Thread(new Runnable() { @Override public void run() { test.read(); } }, "ReadThread1"); Thread t2 = new Thread(new Runnable() { @Override public void run() { test.read(); } }, "ReadThread2"); Thread t3 = new Thread(new Runnable() { @Override public void run() { test.write(); } }, "WriteThread1"); Thread t4 = new Thread(new Runnable() { @Override public void run() { test.write(); } }, "WriteThread4"); t1.start(); t2.start(); }
输出
ReadThread1 开始读了。。。ReadThread2 开始读了。。。ReadThread1 读结束了。。。ReadThread2 读结束了。。。
结论:读读共享
测试2
t2.start();t3.start();
输出
ReadThread2 开始读了。。。ReadThread2 读结束了。。。WriteThread1 开始写了。。。WriteThread1 写完了。。。
结论:读写互斥
测试3
t4.start();t3.start();
输出
WriteThread4 开始写了。。。WriteThread4 写完了。。。WriteThread1 开始写了。。。WriteThread1 写完了。。。
结论:写写互斥
注意:新生成变量时,要用final修饰
final ReentrantReadWriteLockTest test = new ReentrantReadWriteLockTest();
原因:从内部类访问本地变量,本地变量要被声明为final类型