多线程AQS

我们在多线程编程中或多或少的会用到锁,最普遍的应用就是sychronized,但是其自身的非公平锁,可重入锁的特性,使其无法适应复杂的业务场景,例如公平锁,读写锁等等,而我们的jdk提供了AbstractQueuedSynchronizer(此后简称AQS),使我们可以进行扩展实现不同类型的锁以满足业务场景的需求。JDK提供的CountDownLatch,CyclicBarrier,ReentrantLock,Readwritelock,Semaphore,以及Condition都用到了类似AQS这个抽象类,这里我们就为大家解读下AQS源码,并从源码角度分析以上这几种锁的实现方式。废话不多说直接上图:
在这里插入图片描述
其实变量并不多可以大致分为3类,head,tail,链表的元素,每个线程都可以是该链表的一个节点,state锁的状态,unsafe及其以下的成员变量是通过反射直接内存数据的操作。而其中大量的方法无非也就是对链表的操作和state的修改,而state可以是重入锁的重入次数,也可以使读写锁读锁数量和写锁数量(前八位读数后八位写数,总之state是万能的),而为了满足锁的原子性采用的一些CAS操作。
Condition 替代了传统Lock,Lock的wait notify需要配合sychronized使用,而Condition省去了这些还进行了一些扩展入notifyAll等。
ReentrantLock可重入锁,又称作独占锁,一个标识位标识线程,一个标识位标识重入次数,只有线程标识位为空其他线程才可以获取锁。
Readwritelock读写锁,分为两部分读锁和写锁。读锁为共享锁,写锁为独占锁。获取写锁时先判断读锁数量如果>0无法获取,获取读锁时如果写锁数量>0并且读锁不是当前线程无法获取,然后进入等待队列直到被唤醒,在编程时候注意锁降级(在释放写锁前先获取读锁可以节省不必要的开销)。
在CountDownLatch中,此时state用来标记通信线程的数量,只有指定数量的的线程都countdown()后才会释放锁,此时循环锁也就是对外暴露的wait()所在的线程才会继续执行。
CyclicBarrier采用ReentrantLock和condition实现分批次运行,只有指定数量的线程都执行到await()方法后才会继续执行,其余线程进入等待队列。
Semaphore又叫令牌桶,时常高并发访问中被用作限流同一时间只能有指定数量的线程执行,其余线程呗放入等待队列。

相关推荐
©️2020 CSDN 皮肤主题: 游动-白 设计师:白松林 返回首页