转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6558073.html
普通的锁在对某一内容加锁后,其他线程是不能访问的。但是我们要考虑这种情况:如果当前加锁的内容中,有些操作是可以并发执行的,有些是不可以并发,两种操作之间又存在互斥,怎么才能最优化地加锁呢?我们引入了ReadWriteLock,人为地将这两种操作划分为 读、写 操作。(注意:这里的读、写 不是完全意义上的读写,只是用来标识两种加锁的操作),根据操作所加锁的不同,操作之间的互斥关系如下:读——读不互斥;读——写互斥;写——写互斥。也就是说,只有加了读锁的代码块之间可以并发执行,加了读锁的代码块与加了写锁的代码块互斥,加了写锁的代码块之间也互斥执行。
一:使用
创建读写锁:ReadWriteLock接口继承自Lock接口,实现类是ReentrantReadWriteLock。所以使用ReentrantReadWriteLock来创建读写锁,可以在构造函数中指明是否是公平锁。
获取读锁:读锁通过ReentrantReadWriteLock对象的 readLock() 返回一个Lock接口的实现类。
获取写锁:写锁通过ReentrantReadWriteLock对象的 writeLock() 返回一个Lock接口的实现类。
加锁:在需要加锁的地方用读/写锁的lock()加锁。
释放锁:在需要解锁的地方用读/写锁的 unlock()解锁。
二:例子
private static ReentrantReadWriteLock readWriteLock=new ReentrantReadWriteLock(); private static Lock readLock = readWriteLock.readLock(); private static Lock writeLock = readWriteLock.writeLock(); public void run() { if (ischeck) { //上读锁 readLock.lock(); System.out.println("读:" + name + "正在查询" + myCount + "账户,当前金额为" + myCount.getCash()); //释放读锁 readLock.unlock(); } else { //上写锁 writeLock.lock(); System.out.println("写:" + name + "正在操作" + myCount + "账户,金额为" + iocash +",当前金额为" + myCount.getCash()); myCount.setCash(myCount.getCash() + iocash); System.out.println("写:" + name + "操作" + myCount + "账户成功,金额为" + iocash +",当前金额为" + myCount.getCash()); //释放写锁 writeLock.unlock(); } }
三:JDK8中的改进——StampedLock
StampedLock是ReadWriteLock的一个改进。StampedLock与ReadWriteLock的区别在于,StampedLock认为读不应阻塞写。StampedLock认为读写互斥应该是指——不让读重复读同一数据,而不是不让写线程写。
StampedLock是一种偏向于写线程的改进,解决了读多写少时,使用ReadWriteLock会产生写线程饥饿现象。