原文链接:https://mp.weixin.qq.com/s/Z-JHhsLnUVWaqJ5TObPaSg
在开始分析ReentrantLock独占锁之前,我们先来简单了解几个概念:
-
乐观锁与悲观锁
悲观锁指对数据被外界修改持保守态度,认为数据很容易就会被其他线程修改,所以在数据被处理前先对数据进行加锁,并在整个数据处理过程中,使数据处于锁定状态。例如Synchronized。
乐观锁是相对悲观锁来说对,它认为数据在一般情况下不会造成冲突,所以在访问数据前不会加排他锁,而是在进行数据提交更新时,才会正式对数据冲突与否进行检测。例如CAS机制就是乐观锁对一种实现。
-
独占锁与共享锁
根据锁只能被单个线程持有还是能被多个线程共同持有,锁可以分为独占锁和共享锁:
独占锁是一种悲观锁,保证任何时候只有一个线程能得到锁。
共享锁则是一种乐观锁,允许多个线程同时进行读操作。
-
公平锁与非公平锁
根据线程获取锁的抢占机制,锁可以分为公平锁和非公平锁:
公平锁表示线程获取锁的顺序是按照线程请求锁的实践早晚来决定的,也就是最早请求锁的线程将最早获取到锁。
非公平锁在运行时闯入,也就是先来不一定先得。
AbstractQueuedSynchronizer
AbstractQueuedSynchronizer抽象同步队列简称AQS,它是实现同步器的基础组件,锁的底层就是使用AQS实现的。
AQS的使用依靠继承来完成,子类通过继承自AQS并实现所需的方法来管理同步状态;从使用上来说,AQS可以分为两种:独占和共享。
AQS维护了一个FIFO的双向队列和state状态信息,并且通过节点head和tail记录队首和队尾的元素。
FIFO队列元素的类型为Node。其中Node中的thread变量用来存放当前节点对应的线程;Node节点内部的SHARED用来标记该线程时获取共享资源时被阻塞挂起后放入AQS队列的;EXCLUSIVE用来标记线程时获取独占资源时挂起后放入AQS队列的;waitStatus记录当前线程等待状态,可以为CANCELLED(线程被取消了)、SIGNAL(线程需要被唤醒)、CONDITION(线程在条件队列里面等待)、PROPAGATE(释放共享资源时需要通知其他节点);prev记录当前节点的前驱节点;next记录当前节点的后继节点。
在AQS中维护了一个单一的状态信息state,可以通过getState、setState、compareAndSetState函数修改其值。state的含义由子类去定义,自己只是提供了对state的维护。
2
ReentrantLock获取独占锁的实现
ReentrantLock是使用AQS实现的可重入的独占锁,同时只能有一个线程可以获取该锁,其他获取该锁的线程会被阻塞而被放入该锁的AQS阻塞队列里面。其内部可根据构造参数来决定创建的是一个公平锁还是非公平锁,默认是非公平锁。
首先看下ReentrantLock的类图以便对它的实现有个大致了解。