最近研究了一下java中的锁,在看读写锁的代码时,发现很难理解javadoc中关于这个类的解释。于是自己对着代码理解了一下,在此记录,有些地方看得不是太明白,如有错误请纠正。
从不同的视角看锁,锁具有如下特性:
公平性:
公平锁和非公平锁:如果获取锁的顺序是按照请求锁的顺序进行的,那么就是公平锁,否则就是非公平锁
互斥性:
独占锁和共享锁:独占锁只能由一个线程持有,如果独占锁是可重入锁(同一线程可以获取多次),则同一线
程可以获取多次。
共享锁可由多个线程获取。
ReentrantReadWriteLock可以提高锁的并发性,读读共享,读写、写写互斥。非公平锁会优先为等待时间最
长的那个写线程分配写入锁(由非公平读锁的实现决定)。
读写锁的公平性:
非公平读锁:非公平读获取读锁时,判断队列头结点是不是独占结点,是则自旋等待。
非公平写锁:非公平写获取锁时,先尝试直接获取写锁。
公平读锁:不是等待队列的头结点时,不能获取读锁。
公平写锁:不是等待队列的头结点时,不能获取写锁。
锁降级:
锁降级获取锁的顺序:
writelock.lock();
readlock.lock();
writelock.unlock();
readlock.unlock();
锁降级获取写锁时,不能有线程再获取读锁,当修改完数据时,当前线程获取读锁后,可继续执行操作。
不会被其它写线程影响,因为此时其它写线程获取不到锁。
锁升级:
锁升级是不允许的,这里看源代码的时候比较困惑,代码里实际上是可以获取取锁的。不过,这里存在
一个死锁条件,锁升级获取锁的顺序如下:
readlock.lock();
writelock.lock();
readlock.unlock();
writelock.unlock();
为什么会死锁?
因为要想获取写锁,要释放所有读锁,当多个线程同时获取到读锁再获取写锁时,会在获取写锁处等待读
锁释放,导致死锁。
//读写锁用高16位表示共享锁,低16位表示独占锁 static final int SHARED_SHIFT = 16; static final int SHARED_UNIT = (1 << SHARED_SHIFT); //可表示锁的最大值 static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1; static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1; //计算共享锁数量 static int sharedCount(int c) { return c >>> SHARED_SHIFT; } //计算独占锁数量 static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; } /** 获取独占锁 **/ protected final boolean tryAcquire(int acquires) { Thread current = Thread.currentThread(); int c = getState(); int w = exclusiveCount(c); if (c != 0) { // (Note: if c != 0 and w == 0 then shared count != 0) if (w == 0 || current != getExclusiveOwnerThread()) return false; if (w + exclusiveCount(acquires) > MAX_COUNT) throw new Error("Maximum lock count exceeded"); } if ((w == 0 && writerShouldBlock(current)) || !compareAndSetState(c, c + acquires)) return false; setExclusiveOwnerThread(current); return true; } 1.如c不等于0,w等于0,此时线程持有共享锁,不能获取独占锁 2.如c不等于0,获取锁的数量大于最大锁数量,抛异常 3.如果w等于0(其它线程未持有独占锁),这时看写是不是应该被阻塞 4.如果更新锁状态成功,返回true 5.如果c等于0,返回true /** 获取共享锁 **/ protected final int tryAcquireShared(int unused) { Thread current = Thread.currentThread(); int c = getState(); if (exclusiveCount(c) != 0 && getExclusiveOwnerThread() != current) return -1; if (sharedCount(c) == MAX_COUNT) throw new Error("Maximum lock count exceeded"); if (!readerShouldBlock(current) && compareAndSetState(c, c + SHARED_UNIT)) { HoldCounter rh = cachedHoldCounter; if (rh == null || rh.tid != current.getId()) cachedHoldCounter = rh = readHolds.get(); rh.count++; return 1; } return fullTryAcquireShared(current); } 1.如果写锁由其它线程持有,获取失败 2.如果共享锁是最大值,获取失败 3.判断读锁是否该阻塞,公平锁判断该线程是否为头结点,是头结点获取成功,不是则阻塞 非公平锁判断头结点的下一等待结点是否在共享模式下等待,是则成功,不是则阻塞
相关推荐
读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁ReentrantReadWriteLock&StampLock详解_e读写锁...
【深入浅出ReentrantReadWriteLock源码解析】 ReentrantReadWriteLock是Java并发包中的一个核心类,它提供了读写锁的实现,使得多个线程可以并发读取共享资源,但写操作是互斥的,即同一时间只能有一个线程进行写...
根据提供的文件信息,本文将详细解析读写锁`ReentrantReadWriteLock`以及`StampLock`在Java并发编程中的应用场景及其实现原理。 ### 一、读写锁介绍 #### 1.1 读写锁的基本概念 读写锁是一种特殊的锁机制,它可以...
在Java多线程并发编程中,ReentrantReadWriteLock(可重入读写锁)是一个重要的同步工具,它属于Java并发包(java.util.concurrent.locks)中的一个类。这个锁提供了比标准的synchronized关键字更细粒度的控制,允许...
ReadWriteLock 接口及其实现 ReentrantReadWriteLock 方法 在 Java 并发编程中,锁机制是非常重要的一种同步机制,用于解决多线程之间的资源竞争问题。在 Java 中,有多种锁机制,如 ReentrantLock、...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
Java的ReentrantReadWriteLock是Java并发包`java.util.concurrent.locks`中的一个重要工具,它提供了一种更细粒度的锁定机制,相比普通的独占锁(如ReentrantLock)在某些场景下能显著提高程序的并发性能。...
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,非常具有实用价值,需要的朋友可以参考下
ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock(); ``` 然后通过以下方式获取读锁和写锁: ```java ReentrantReadWriteLock.ReadLock readLock = reentrantReadWriteLock.readLock...
本文将深入探讨Java中的两种读写锁:ReentrantReadWriteLock和StampedLock,并分析它们的工作原理、特点以及如何在实际开发中进行应用。 一、ReentrantReadWriteLock(可重入读写锁) 1. **简介**: ...
内容包括 01-并发编程之深入理解JMM&并发三大特性(一)-fox 02-并发编程之深入理解JMM&并发三...11-深入理解AQS之CyclicBarrier&ReentrantReadWriteLock详解-fox 12-深入理解AQS之ReentrantReadWriteLock详解-fox ...
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); ReadLock readLock = lock.readLock(); WriteLock writeLock = lock.writeLock(); ``` 2. **读者部分**:当一个线程想要读取数据时,它需要获取读锁...
ReentrantReadWriteLock lock = new ReentrantReadWriteLock(true); // 公平锁 ``` 然后,我们可以定义读操作和写操作的方法: 对于读者: ```java public void read() { lock.readLock().lock(); try { // 读取...
- `ReentrantReadWriteLock`是Java提供的可重入的读写锁实现,它继承自`AbstractQueuedSynchronizer`(AQS)。可重入意味着一个线程可以多次获取同一锁,这在递归调用或者锁嵌套时很有用。 - **公平性**:`...