最近在看<<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 中,有多种锁机制,如 ReentrantLock、...
Java的ReentrantReadWriteLock是Java并发包`java.util.concurrent.locks`中的一个重要工具,它提供了一种更细粒度的锁定机制,相比普通的独占锁(如ReentrantLock)在某些场景下能显著提高程序的并发性能。...
【深入浅出ReentrantReadWriteLock源码解析】 ReentrantReadWriteLock是Java并发包中的一个核心类,它提供了读写锁的实现,使得多个线程可以并发读取共享资源,但写操作是互斥的,即同一时间只能有一个线程进行写...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
根据提供的文件信息,本文将详细解析读写锁`ReentrantReadWriteLock`以及`StampLock`在Java并发编程中的应用场景及其实现原理。 ### 一、读写锁介绍 #### 1.1 读写锁的基本概念 读写锁是一种特殊的锁机制,它可以...
在Java多线程并发编程中,ReentrantReadWriteLock(可重入读写锁)是一个重要的同步工具,它属于Java并发包(java.util.concurrent.locks)中的一个类。这个锁提供了比标准的synchronized关键字更细粒度的控制,允许...
6.5 深入理解 AQS之 ReentrantReadWritelock 实战副本.mp4
6.5 深入理解 AQS之 ReentrantReadWritelock 实战副本副本.mp4
ReentrantReadWriteLock 读写锁除了保证写操作对读操作可见性以及并发行提升外,简化了读写交互场景开发
ReadWriteLock的使用,实际上由于ReadWriteLock是一个接口,所以实际使用的是ReentrantReadWriteLock子类。同时ReadWriteLock的使用其实也是比较简单的,就是读写的锁的使用以及注意事项而已。
`ReentrantLock`和`ReentrantReadWriteLock`是Java并发包`java.util.concurrent.locks`中的两个重要工具,它们提供了比标准`synchronized`关键字更高级别的锁控制机制。本文将深入探讨这两个类,以及如何通过配置...
本篇文章主要介绍了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 ...
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); ``` 然后通过以下方式获取读锁和写锁: ```java ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock...
8. Lock接口 (ReentrantLock 可重入锁) 特性 ReentantLock 继承接口 Lock 并实现了接口中定义的方法, 它是一种可重入锁, 除了能完成 synchronized 所能完成的所有工作外,还提供了诸如可响应中断锁、可轮询锁...
本文将深入探讨Java中的两种读写锁:ReentrantReadWriteLock和StampedLock,并分析它们的工作原理、特点以及如何在实际开发中进行应用。 一、ReentrantReadWriteLock(可重入读写锁) 1. **简介**: ...
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); ReadLock readLock = lock.readLock(); WriteLock writeLock = lock.writeLock(); ``` 2. **读者部分**:当一个线程想要读取数据时,它需要获取读锁...
ReentrantLock//互斥锁 class CachedData { Object data; volatile boolean cacheValid; ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();