前言:大家好,我是小威,24届毕业生,曾经在某央企公司实习,目前刚拿到某税务公司的实习offer。本篇文章将分享读写锁相关的知识点。
本篇文章记录的基础知识,适合在学Java的小白,也适合复习中,面试中的大佬。
如果文章有什么需要改进的地方还请大佬不吝赐教。
小威在此先感谢各位大佬啦~~
个人主页:小威要向诸佬学习呀
个人简介:大家好,我是小威,一个想要与大家共同进步的男人
目前状况:24届毕业生,曾经在某央企公司实习,目前在另外一家满意的公司实习欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客,我亲爱的大佬
以下正文开始
读写锁,顾名思义,包含两种锁,一种叫做读锁,一种叫做写锁。其中读锁是共享锁,写锁是排他锁。当持有读锁时,能够对共享资源进行读操作,持有写锁时,能够对共享资源进行写操作。读锁在同一时刻允许多个线程进行读操作获取锁资源,而写锁在同一时刻只允许一个线程获取到锁资源。
由于读写锁在同一时刻能够允许多个线程同时读取共享资源,而排它锁只允许一个线程获取到锁资源,所以在高并发的情况下,读写锁性能比排它锁要好一些。
读写锁是一个接口(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; }
由于篇幅原因,本篇文章就先分享到这里了,后续会分享读写锁加锁和释放锁流程的知识,感谢大佬认真读完支持咯~
文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起讨论
希望能和诸佬们一起努力,今后进入到心仪的公司
再次感谢各位小伙伴儿们的支持