本文正在参加「金石计划」
读写锁简单介绍
读写锁,顾名思义,包含两种锁,一种叫做读锁,一种叫做写锁。其中读锁是共享锁,写锁是排他锁。当持有读锁时,能够对共享资源进行读操作,持有写锁时,能够对共享资源进行写操作。读锁在同一时刻允许多个线程进行读操作获取锁资源,而写锁在同一时刻只允许一个线程获取到锁资源。
由于读写锁在同一时刻能够允许多个线程同时读取共享资源,而排它锁只允许一个线程获取到锁资源,所以在高并发的情况下,读写锁性能比排它锁要好一些。
读写锁源码讲解
读写锁是一个接口(ReadWriteLock),其位于java. util.concurrent.locks包下,ReadWriteLock接口中包含两个方法,分别为readLock()来获取读锁,writeLock()方法获取写锁,其源码如下:
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
ReadWriteLock读写锁接口的实现类是ReentrantReadWriteLock,在前面我们介绍过ReentranLock,他是一个支持多种方式获取锁的类,提到ReentranLock,我们在这里回顾一下Lock和synchronized的区别:
Lock和synchronized锁的区别:
synchronized本质上是关键字,而Lock锁是接口; synchronized可以作用于方法和代码块上,而Lock锁只能作用于代码块上; synchronized锁和Lock锁的底层不同,synchronized底层是基于objectMonitor对象锁来实现的,而Lock锁是基于AQS,FIFO先进先出队列实现的; synchronized只支持非公平锁,而Lock锁支持公平锁和非公平锁; synchronized是阻塞式加锁,而Lock是非阻塞式加锁,并且支持可中断式加锁,支持超时时间加锁; synchronized在加锁和解锁时,只有一个同步队列和一个等待队列,而Lock锁有一个同步队列和支持多个等待队列(condition); synchronized锁在进行等待和唤醒时,使用的是object类中的wait()和notify()方法,而lock锁使用的是condition接口的await()和signal()方法。
回归正题,我们来看一下ReentrantReadWriteLock实现类的源码:
public ReentrantReadWriteLock() {
this(false);
}
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
ReentrantReadWriteLock支持公平锁和非公平锁的实现,可以根据fair变量使用三目运算符进行判断来创建公平锁和非公平锁,也可以使用默认创建方式,不传入参数直接创建非公平锁。
ReentrantReadWriteLock的内部实现同时依赖于内部类Sync,如下:
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** Performs all synchronization mechanics */
final Sync sync;
我们点入Sync类查看源码可以看到,Sync是继承了AbstractQueuedSynchronizer的,因此ReentrantReadWriteLock实现类仍然依赖于AQS来实现。
在ReentrantReadWriteLock中实现读锁和写锁,需要维护一个读状态和写状态,在ReentrantReadWriteLock中,使用state高16位表示读状态(获取读锁的次数),使用state的低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;
/** Returns the number of shared holds represented in count */
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
/** Returns the number of exclusive holds represented in count */
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
由于篇幅原因,本篇文章就先分享到这里了,后续会分享读写锁加锁和释放锁流程的知识,感谢大佬认真读完支持咯~ 、
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起讨论🍻 希望能和诸佬们一起努力,今后进入到心仪的公司 再次感谢各位小伙伴儿们的支持🤞