最近在看<<Java并发编程实践>>,有这样一个类:ReentrantReadWriteLock。在这里做一个小结:
线程获得写锁的前提条件:
其他线程没有获得读锁:注意一定是其他线程!!!!!!!!!!!!!!!
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); static class MyThread extends Thread{ public void run() { readLock.lock(); //readLock.unlock(); } } public static void main(String args[]){ new MyThread().start(); writeLock.lock(); //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。 System.out.println("here"); } } //运行结果: //程序进入死锁,writeLock一直等待。 //只要将readLock.unlock()的注释解开,程序就跑通了。 //可见:要想获得写锁,别的线程必须没有获得读锁。
其他线程没有获得写锁:
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); static class MyThread extends Thread{ public void run() { writeLock.lock(); //writeLock.unlock(); } } public static void main(String args[]){ new MyThread().start(); writeLock.lock(); //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。 System.out.println("here"); } } //运行结果: //效果同上,发生死锁.若解开writeLock.unlock()的注释则程序正常,成功输出here
线程进入读锁的前提条件:
其他线程没有获得写锁:
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); static class MyThread extends Thread{ public void run() { writeLock.lock(); //writeLock.unlock(); } } public static void main(String args[]){ new MyThread().start(); readLock.lock(); //通过debug,发现程序阻塞在这里了,发生死锁。下面的"here"打印不出来。 System.out.println("here"); } } //结果同上,获得读锁的前提是没有别的线程获得写锁
没有写请求或者有写请求,但调用线程和持有锁的线程是同一个:
这一条完全不明白是什么意思。
*******************************************************************************
还有一个特性:一个线程可以先获得写锁,再获得读锁,比如这样:
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); public static void main(String args[]){ writeLock.lock(); readLock.lock(); System.out.println("here"); } } //运行结果:程序正常 here
但是:一个线程不能先获得读锁再获得写锁,像这样:
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); public static void main(String args[]){ readLock.lock(); writeLock.lock(); System.out.println("here"); } } //运行结果: //程序进入死循环
因为一个线程可以先获得写锁,再获得读锁。所以:可以实现降级锁,即: 从写入锁降级为读取锁,其实现方式是:先获取写入锁,然后获取读取锁,最后释放写入锁。像这样:
public class ReadWriteLock{ static ReentrantReadWriteLock myLock=new ReentrantReadWriteLock(); static Lock readLock=myLock.readLock(); static Lock writeLock=myLock.writeLock(); public static void main(String args[]){ writeLock.lock(); readLock.lock(); writeLock.unlock(); System.out.println("here"); } } //运行结果: here
但是,从读取锁升级到写入锁是不可能的。
最后一点:ReadLock可以被多个线程持有并且在作用时排斥任何的WriteLock,而WriteLock则是完全的互斥。这一特性最为重要,因为对于高读取频率而相对较低写入的数据结构,使用此类锁同步机制则可以提高并发量。
下面根据一个网上的例子说明这一点:
public class ReentrantReadWriteLockSample { public static void main(String[] args) { testReadLock(); // testWriteLock(); } public static void testReadLock() { final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport(); Runnable runnable = new Runnable() { public void run() { support.get("test"); } }; new Thread(runnable).start(); new Thread(runnable).start(); new Thread(new Runnable() { public void run() { support.put("test", "test"); } }).start(); } public static void testWriteLock() { final ReadWriteLockSampleSupport support = new ReadWriteLockSampleSupport(); new Thread(new Runnable() { public void run() { support.put("key1", "value1"); } }).start(); new Thread(new Runnable() { public void run() { support.put("key2", "value2"); } }).start(); new Thread(new Runnable() { public void run() { support.get("key1"); } }).start(); } } class ReadWriteLockSampleSupport { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final Lock readLock = lock.readLock(); private final Lock writeLock = lock.writeLock(); private volatile boolean completed= true; private Map<String,String> cache = new HashMap<String,String>(32); public String get(String key) { readLock.lock(); System.out.println(Thread.currentThread().getName() + " read."); startTheCountdown(); //等待5s try{ return cache.get(key); } finally{ readLock.unlock(); } } public String put(String key, String value) { writeLock.lock(); System.out.println(Thread.currentThread().getName() + " write."); startTheCountdown(); try{ return cache.put(key, value); } finally { writeLock.unlock(); } } /** * A simple countdown,it will stop after about 5s. */ public void startTheCountdown() { long currentTime = System.currentTimeMillis(); for(;;) { long diff = System.currentTimeMillis() - currentTime; if(diff > 5000) { break; } } } } // testReadLock(); 和 testWriteLock(); 分开运行
ReentrantReadWriteLockSample中的两个静态测试方法则分别测试了ReadLock和WriteLock的排斥性。 testReadLock()中,开启三个线程,前两者试图获取ReadLock而后者去获取WriteLock。执行结果可以看 到:ReadWriteLockSampleSupport的get()方法中的打印结果在前两个线程中几乎同时显示,而put()中的打印结果则要等上 近5s。这就说明了,ReadLock可以多线程持有并且排斥WriteLock的持有线程。testWriteLock()中,也开启三个线程。前两个 是去获取WriteLock,最后一个获取ReadLock。执行的结果是三个打印结果都有近5s的间隔时间,这说明了WriteLock是独占的。
相关推荐
读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁...
下面小编就为大家带来一篇ReadWriteLock接口及其实现ReentrantReadWriteLock方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
主要介绍了Java多线程 ReentrantReadWriteLock原理及实例详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
针对这种场景,JAVA的并发包提供了读写锁ReentrantReadWriteLock,它表示两个锁,一个是读操作相关的锁,称为共享锁;一个是写相关的锁,称为排他锁 类图如下: 说明:如上图所示Sync为ReentrantReadWriteLock...
6.5 深入理解 AQS之 ReentrantReadWritelock 实战副本.mp4
6.5 深入理解 AQS之 ReentrantReadWritelock 实战副本副本.mp4
ReentrantReadWriteLock 读写锁除了保证写操作对读操作可见性以及并发行提升外,简化了读写交互场景开发
6.JUC并发工具类在大厂的应用场景详解 (1).pdf ...8、读写锁ReentrantReadWriteLock&StampLock详解.pdf 9、并发容器 (Map、List、Set) 实战及其原理.pdf 10、阻塞队列BlockingQueue 实战及其原理分析.pdf
Java 多线程与并发(12_26)-JUC锁_ ReentrantReadWriteLock详解
8. Lock接口 (ReentrantLock 可重入锁) 特性 ReentantLock 继承接口 Lock 并实现了接口中定义的方法, 它是一种可重入锁, 除了能完成 synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁...
什么是读锁和写锁 对于资源的访问就两种形式:要么是读操作,要么是写操作。读写锁是将被锁保护的临界资源的读操作和写操作分开,允许同时有多个线程同时对临界资源进行读操作,任意时刻只允许一个线程对资源进行写...
ReadWriteLock的使用,实际上由于ReadWriteLock是一个接口,所以实际使用的是ReentrantReadWriteLock子类。同时ReadWriteLock的使用其实也是比较简单的,就是读写的锁的使用以及注意事项而已。
争用分析 ReentrantLock 和 ReentrantReadWriteLock 上的配置文件争用
本篇文章主要介绍了Java concurrency之共享锁和ReentrantReadWriteLock,非常具有实用价值,需要的朋友可以参考下
1.5 小结 11 第2章 基本数据类型——构建Java 大厦的基础 12 2.1 源代码注释 12 2.1.1 单行注释 12 2.1.2 区域注释 12 2.1.3 文档注释 13 2.2 基本数据类型 14 2.2.1 整型 15 2.2.2 浮点型 17 ...
ReentrantLock//互斥锁 class CachedData { Object data; volatile boolean cacheValid; ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
加密N上载 encrypt-N-upload是一个演示应用程序,它最初是一个集成应用程序,可以将身份验证请求从内部服务器代理到外部授权服务。 该应用程序还接受文件上传,然后将其转发到外部服务。 原始形式的应用程序非常...
ReentrantReadWriteLock.WriteLock 隐式锁(内置锁) Synchronized 问题 死锁 性能 线程活跃与线程饥饿 同步工具类 原子操作类 AtomicInteger等 相当于加上synchronized 也有些利用硬件底层能力CAS
hadoop3.1.1基于hdp3.1.5版本的ReentrantReadWriteLock还原成hadoop2.x版本的synchronized锁