ReentrantLock
ReentrantLock实现了Lock, Lock下面还有好多实现锁,比如读锁,写锁…
ReentrantLock是重入锁,也是互斥锁,锁实现基于内部类FairSync(公平锁)和NonFairSync(非公平锁)实现,
重入锁: 当前线程获得了执行序列的锁,那么该执行序列中的所有方法都可以获取此锁,简单的说就是该线程获取锁执行某个资源,该资源类部还是可以获取该锁,
互斥锁: 一次最多只能有一个线程获取锁, synchronize关键字和Lock都是互斥锁
公平锁: 基于AQS(AbstractQueuedSynchronizer)同步器队列实现, 该队列中维护的是Node(节点),每一个node中维护的值就是当前请求获取锁的线程(我咋感觉是个双向链表),该队列遵循FIFO(先进先出),公平锁就是每次只从队首取值,新来的线程先入队等待
非公平锁: 非公平锁同样基于AQS实现, 但是在新线程加入的时候回发生锁的争夺, 并不是进行入队操作, 新线程很大程度上都能够获取锁, 而原有队列中的线程则不会被唤醒,继续等待, 当新的线程获取锁失败后,才会加入队列,队列中的线程还是会遵循先进先出,
锁实现机制都是通过node节点, state锁状态,以及cas操作等实现
详细介绍请查看Java中的公平锁和非公平锁实现详解
所有源码我都直接去掉英文注释了,不然那注释太多我,关键是我也看不懂,需要用软件翻译,一行一行的看,我就注释一个大概的意思
首先看看Lock这个类的源码:
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
public interface Lock {
// 加锁,获取锁, 该方法常用
void lock();
void lockInterruptibly() throws InterruptedException;
//尝试获取锁,成不成功看天意
boolean tryLock();
//尝试在某个事件段内获取锁,成不成功看天意
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
//释放锁 该方法常用
void unlock();
// 这个condition是个非常好用的工具,后面再讲,他里面的方法类似于object的wait,notify,notifyAll
Condition newCondition();
}
ReentrantLock实现了lock,看看ReentrantLock的源码:
注释应该比较清楚
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** 同步器实例, Sync就下面的一个内部类,实现了aqs */
private final Sync sync;
/**
* aqs是此锁的同步控制基础。 在下面细分为公平和非公平版本。 使用AQS状态表示锁的保留数。
* sync为ReentrantLock内部类, sync继承AQS AQS中维护了Node节点,state锁持有状态 =0没有线程持有该锁 >0 有线程持有该锁, 对state的操作是cas操作
*
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* 执行{@link Lock#lock}。 子类化的主要原因是为非公平版本提供快速路径。
*/
abstract void lock();
/**
* 执行不公平的tryLock。 tryAcquire是在子类中实现的,但是都需要对trylock方法进行不公平的尝试。
* state属性的总结:
* 1. 因为存在多线程竞争的情形,使用CAS设置值
* 2. state初始值为0,线程加一次锁,state加1,获得锁的线程再次加锁,state值再次加1。所以state表示已获得锁线程进行lock操作的次数
* 3. 是volatile修饰的变量,线程直接从主存中读
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); //锁状态标识 aqs中维护 初始值为0 state对所有线程可见的一个状态
if (c == 0) { //状态为0
if (compareAndSetState(0, acquires)) { //cas原子更新操作,该对象在内存中的值和期望值0相等,则将值替换为acquires, 这里不懂的cas等下再讲
setExclusiveOwnerThread(current); //将当前线程设置为当前拥有独占访问权的线程
return true; //返回true
}
}else if (current == getExclusiveOwnerThread()) { //判断当前线程是不是拥有独占访问权的线程
int nextc = c + acquires;
if (nextc < 0) // overflow 状态小于0,溢出
throw new Error("Maximum lock count exceeded");//抛出异常"超出最大锁计数"
setState(nextc);// 如果是取得锁的线程,再次获取锁,直接使用set方法设置
return true;
}
return false;
}
//释放锁 state-1其实就是
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())//该操作只针对当前持有锁的线程
throw new IllegalMonitorStateException();//否则报错
boolean free = false;
if (c == 0) { //2.锁状态是不是等于0,true就是没有线程持有锁了,为false的情况就是当前线程获取的资源内部重入该锁了,
free = true;
setExclusiveOwnerThread(null);
}
setState(c)//更改状态为c
return free;
}
protected final boolean isHeldExclusively() {
// While we must in general read state before owner,一般来说我们必须要检查当前线程的状态
// we don't need to do so to check if current thread is owner,但我们不需要这样做来检查当前线程是否为锁的持有者
return getExclusiveOwnerThread() == Thread.currentThread(); //判断当前线程是否是持有锁的线程
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// Methods relayed from outer class
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//检查线程持有锁的状态
final int getHoldCount() {
//当前线程持有锁,返回state, 否 返回0
return isHeldExclusively() ? getState() : 0;
}
final boolean isLocked() {
return getState() != 0;
}
/**
* Reconstitutes the instance from a stream (that is, deserializes it).
*/
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // reset to unlocked state
}
}
/**
* Sync object for non-fair locks
* ReentrantLockde的非公平锁内部类 为非公平锁同步对象
*/
static final class NonfairSync extends Sync {
private static final long serialVersionUID = 7316153563782823691L;
/**
* Performs lock. Try immediate barge, backing up to normal
* acquire on failure.
*/
final void lock() {
if (compareAndSetState(0, 1)) //直接就进行原子操作获取锁
setExclusiveOwnerThread(Thread.currentThread());//成功就直接设置当前线程为锁的持有者
else
acquire(1); //aqs中的方法,意为获取,该方法中调用tryAcquire(int acquires)尝试再次获取锁,成功则返回,不成功则循环尝试加入队列,调用acquireQueued(Node , arg),
}
//重写aqs的 tryAcquire方法
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires); //直接调用aqs的非公平实现获取锁方法再次尝试获取锁,
}
}
/**
* ReentrantLockde 公平锁内部类 为公平锁同步对象
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 重写aqs的 公平的tryAcquire方法
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() && // !hasQueuedPredecessors(),判断此昂前线程在队列中是不是第一个,不是第一个保证了不论是新的线程还是已经排队的线程都顺序使用锁
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
}
//创建一个非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//创建一个公平锁还是非公平锁,看你自己的选择,传入true就是公平锁,
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//
public void lock() {
sync.lock();
}
//尝试获取锁,如果获取到锁,返回true
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
//在指定时间类获取锁,如果获取返回true
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
//释放锁
public void unlock() {
sync.release(1);
}
//
public Condition newCondition() {
return sync.newCondition();
}
//获取当前线程持有锁次数
public int getHoldCount() {
return sync.getHoldCount();
}
//检查当前线程是否为持有锁的线程
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
//锁是否被线程持有
public boolean isLocked() {
return sync.isLocked();
}
//
public final boolean isFair() {
return sync instanceof FairSync;
}
//返回锁的持有者,即当前持有锁的线程
protected Thread getOwner() {
return sync.getOwner();
}
//查询队列中是否有线程正在等待获取锁
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
//判断某个指定线程是否在队列中等待获取锁
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
//返回队列长度
public final int getQueueLength() {
return sync.getQueueLength();
}
//返回队列里的所有线程
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
//
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
//
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
}
以下都是AQS(AbstractQueuedSynchronized)中的源码
acquire方法 , 以独占模式获取对象,忽略中断。
public final void acquire(int arg) {
if (!tryAcquire(arg) && //当尝试获取锁失败
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire(arg): 尝试获取锁,获取成功直接返回,
addWaiter:将当前线程加入到CLH队列队尾。
acquireQueued:当前线程会根据公平性原则来进行阻塞等待,直到获取锁为止;并且返回当前线程在等待过程中有没有中断过。
selfInterrupt:产生一个中断。
acquireQueued方法
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();//当前节点的前一个节点
if (p == head && tryAcquire(arg)) {//如果p是标杆节点,再次尝试获取锁,
setHead(node);//当前线程获取锁,将node标杆节点,p节点则出队
p.next = null; // help GC 将p的尾节点置位空,等待gc
failed = false;
return interrupted;//返回没有中断过
}
//p节点不是第一个节点,或者再次获取锁失败 则执行shouldParkAfterFailedAcquire和parkAndCheckInterrupt来达到阻塞的效果
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true; //返回线程中断
}
} finally {
if (failed)
cancelAcquire(node);
}
}
图片取至https://blog.csdn.net/ssuperlg/article/details/79542473
标杆节点: 我理解为原来在队列中但是现在获取锁的线程的节点通过setHead(node)设置的节点, 随时准备出队列的节点
而从第二个节点开始才是真正有线程在等待的节点,当正在执行的线程释放锁,将唤醒线程1,同时原标杆节点出队列,线程1这个节点设置为标杆节点,
addWaiter方法, 添加节点值CLH队列中
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode); //创建一个新节点,并将当前线程放入节点中
// Try the fast path of enq; backup to full enq on failure
//尝试快速插入,
//获取同步器中的tail指向的节点,即:未插入新节点时的尾节点(暂且称之为原队列中的尾节点)
Node pred = tail;
if (pred != null) {//如果tail为空,即原有队列没有节点,则直接用enq插入
node.prev = pred;
if (compareAndSetTail(pred, node)) {//原子操作插入节点
pred.next = node;
return node;
}
}
enq(node);//如果快速插入失败,则使用enq插入,enq内部死循环直到插入成功
return node;
}
enq(node)方法;将节点插入队列
这里进行了循环,如果此时存在了tail就执行同上一步骤的添加队尾操作,如果依然不存在,就把当前线程作为head结点。
插入节点后,调用acquireQueued()进行阻塞
private Node enq(final Node node) {
for (;;) {
Node t = tail; //队列的尾节点
if (t == null) { // Must initialize 空队列,必须初始化一个标杆节点
if (compareAndSetHead(new Node()))//原子操作,创建一个空值的节点
tail = head; //
} else {
//如果不是空队列
node.prev = t; //将队列尾节点赋值给要插入的node的前节点
if (compareAndSetTail(t, node)) {//再将node节点插入队列
t.next = node;
return t;
}
}
}
}
详细分析参考:
https://blog.csdn.net/qyp199312/article/details/70598480