什么是网络营销工具,站长之家seo查找,大连开发区信息服务平台,wordpress从哪里登录密码1 介绍
为什么要使用读写锁#xff1f; 需要高并发读取和较低并发写入的应用程序#xff0c;降低锁的粒度#xff0c;提高系统性能
使用场景#xff1a; 读多写少的共享资源 缓存管理#xff1a;读 写#xff0c;控制多个线程同时读缓存#xff0c;需要刷新o…1 介绍
为什么要使用读写锁 需要高并发读取和较低并发写入的应用程序降低锁的粒度提高系统性能
使用场景 读多写少的共享资源 缓存管理读 写控制多个线程同时读缓存需要刷新or修改操作时才使用写锁 数据库连接池多个线程从池中获取连接读操作只有一个线程可以设置连接到池中写操作 文件读写 数据结构的并发访问
2 使用
import java.util.concurrent.locks.ReentrantReadWriteLock;public class SharedResource {private final ReentrantReadWriteLock lock new ReentrantReadWriteLock();private final ReentrantReadWriteLock.ReadLock readLock lock.readLock();private final ReentrantReadWriteLock.WriteLock writeLock lock.writeLock();public void readFromResource() {readLock.lock(); // 获取读锁try {// 执行读取共享资源的操作} finally {readLock.unlock(); // 释放读锁}}public void writeToResource() {writeLock.lock(); // 获取写锁try {// 执行写入共享资源的操作} finally {writeLock.unlock(); // 释放写锁}}
}3 原理分析
读写锁两个状态读状态、写状态
但AQS中只有一个state如何记录两种状态 高低位int4个字节共32位采用高16位控制读低16位控制写 00000000 00000000 00000000 00000000 加锁时如何判断读锁、写锁 高16位0表示有读锁sharedCount() 低16位0表示有写锁exclusiveCount()
如何实现可重入 写锁只有一个线程独占重入则低16位1即可 写锁有多个线程持有如何记录ThreadLocal线程私有
4 读锁源码
读锁tryAcquireShared()、tryReleaseShared()读读共享
protected final int tryAcquireShared(int unused) {Thread current Thread.currentThread();int c getState();//是否其它线程占用排它锁如果是则不允许获取共享锁if (exclusiveCount(c) ! 0 getExclusiveOwnerThread() ! current)return -1;//共享锁被获取的数量int r sharedCount(c);//获取共享锁//1 未阻塞//2 不超最大读计数//3 设置共享锁成功if (!readerShouldBlock() r MAX_COUNT compareAndSetState(c, c SHARED_UNIT)) {//第一次读if (r 0) {firstReader current;firstReaderHoldCount 1;//重入} else if (firstReader current) {firstReaderHoldCount;} else {//其它线程读HoldCounter rh cachedHoldCounter;if (rh null || rh.tid ! getThreadId(current))//记录每个线程的重入次数cachedHoldCounter rh readHolds.get();else if (rh.count 0)readHolds.set(rh);rh.count;}return 1;}//若不满足上述条件则执行方法内的获取共享锁逻辑return fullTryAcquireShared(current);}
final int fullTryAcquireShared(Thread current) {HoldCounter rh null;//1 自旋 获取共享锁or失败for (;;) {int c getState();//2 若存在写锁且不是当前线程持有的不允许获取共享锁if (exclusiveCount(c) ! 0) {if (getExclusiveOwnerThread() ! current)return -1;//3 读线程阻塞} else if (readerShouldBlock()) {if (firstReader current) {} else {if (rh null) {rh cachedHoldCounter;if (rh null || rh.tid ! getThreadId(current)) {rh readHolds.get();if (rh.count 0)readHolds.remove();}}if (rh.count 0)return -1;}}// 4 不允许再申请共享锁if (sharedCount(c) MAX_COUNT)throw new Error(Maximum lock count exceeded);// 5 尝试获取锁if (compareAndSetState(c, c SHARED_UNIT)) {if (sharedCount(c) 0) {firstReader current;firstReaderHoldCount 1;} else if (firstReader current) {firstReaderHoldCount;} else {if (rh null)rh cachedHoldCounter;if (rh null || rh.tid ! getThreadId(current))rh readHolds.get();else if (rh.count 0)readHolds.set(rh);rh.count;cachedHoldCounter rh; // cache for release}return 1;}}}
5 写锁源码
写锁tryAcquire()、tryRelease()写写互斥读写互斥
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);// Reentrant acquiresetState(c acquires);return true;}if (writerShouldBlock() ||!compareAndSetState(c, c acquires))return false;setExclusiveOwnerThread(current);return true;}