3.ReentrantLock源码概览

99 阅读2分钟

ReentrantLock源码概览

AbstractQueuedSynchronizer

public abstract class AbstractQueuedSynchronizer extends AbstractOwnableSynchronizer implements java.io.Serializable {
    private transient volatile Node head;
    private transient volatile Node tail;
    private volatile int state;
}

Node

static final class Node {
        static final Node SHARED = new Node();
        static final Node EXCLUSIVE = null;
        static final int CANCELLED =  1;
        static final int SIGNAL    = -1;
        static final int CONDITION = -2;
        static final int PROPAGATE = -3;
 
        volatile int waitStatus;
    
        volatile Node prev;
 
        volatile Node next;
 
        volatile Thread thread;
    
        Node nextWaiter;
 
        final boolean isShared() {
            return nextWaiter == SHARED;
        }
 
        final Node predecessor() throws NullPointerException {
            Node p = prev;
            if (p == null)
                throw new NullPointerException();
            else
                return p;
        }
​
        Node() {     
        }
        
        //构建同步队列上的Node  Used by addWaiter
        Node(Thread thread, Node mode) {    
            this.nextWaiter = mode;
            this.thread = thread;
        }
        //构建等待队列上的Node  Used by Condition
        Node(Thread thread, int waitStatus) { 
            this.waitStatus = waitStatus;
            this.thread = thread;
        }
    }

Node等待状态waitStatus

Node结点是对每一个等待获取资源的线程的封装,其包含了需要同步的线程本身及其等待状态,如是否被阻塞、是否等待唤醒、是否已经被取消等。

变量waitStatus则表示当前Node结点的等待状态,共有5种取值CANCELLED、SIGNAL、CONDITION、PROPAGATE、0。

  • CANCELLED(1):表示当前结点已取消调度。当timeout或被中断(响应中断的情况下),会触发变更为此状态,进入该状态后的结点将不会再变化。
  • SIGNAL(-1):表示后继结点在等待当前结点唤醒。后继结点入队时,会将前继结点的状态更新为SIGNAL。
  • CONDITION(-2):表示结点等待在Condition上,当其他线程调用了Condition的signal()方法后,CONDITION状态的结点将从等待队列转移到同步队列中,等待获取同步锁。
  • PROPAGATE(-3):共享模式下,前继结点不仅会唤醒其后继结点,同时也可能会唤醒后继的后继结点。
  • 0:新结点入队时的默认状态。创建node时的默认状态
//线程已经被取消
static final int CANCELLED =  1;
//线程需要去被唤醒
static final int SIGNAL    = -1;
//线程正在唤醒等待条件
static final int CONDITION = -2;
//线程的共享锁应该被无条件传播
static final int PROPAGATE = -3;

负值表示结点处于有效等待状态,而正值表示结点已被取消。

所以源码中很多地方用>0、<0来判断结点的状态是否正常,0是新结点入队时的默认状态。

Node指针

同步队列是双向。

volatile Node prev;//同步队列中节点的前置节点
volatile Node next;//同步队列中节点的后置节点

等待队列是单向

Node nextWaiter;//等待队列中节点的后置节点

ReentrantLock

ReentrantLock持有1个Sync实例

public class ReentrantLock implements Lock, java.io.Serializable {
    //同步器
     private final Sync sync;
    //省略代码
}

构造方法

其实是构造1个具体的同步器,默认是非公平锁。

public ReentrantLock() {
    //同步器 Sync extends AbstractQueuedSynchronizer 
    //有2个实现类 
    //static final class NonfairSync extends Sync 
    //static final class FairSync extends Sync
    sync = new NonfairSync();
}

指定公平锁还是非公平锁

public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

Sync

Sync继承自AbstractQueuedSynchronizer

 abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;
        //加锁方法
        abstract void lock();
        //非公平尝试获取锁:非公平的体现:如果当前锁没人占用,不需要排队,直接插队获取锁,
        final boolean nonfairTryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                if (compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }
        //尝试释放锁
        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }
     
        //是否是持有锁的独占者
        protected final boolean isHeldExclusively() {
            return getExclusiveOwnerThread() == Thread.currentThread();
        }
        
        //条件变量
        final ConditionObject newCondition() {
            return new ConditionObject();
        }
​
        //获取当前持有锁的线程
        final Thread getOwner() {
            return getState() == 0 ? null : getExclusiveOwnerThread();
        }
        
        //重入次数
        final int getHoldCount() {
            return isHeldExclusively() ? getState() : 0;
        }
        
        //是否加锁
        final boolean isLocked() {
            return getState() != 0;
        }
​
        //反序列化
        private void readObject(java.io.ObjectInputStream s)
            throws java.io.IOException, ClassNotFoundException {
            s.defaultReadObject();
            setState(0); // reset to unlocked state
        }
    }

NonfairSync

static final class NonfairSync extends Sync {
    private static final long serialVersionUID = 7316153563782823691L;
    //加锁方法
    final void lock() {
        //非公平的体现:上来就立刻做一次cas
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    //尝试加锁方法
    protected final boolean tryAcquire(int acquires) {
        return nonfairTryAcquire(acquires);
    }
}

ReentrantLock加锁的方法是调用同步器的lock方法

public void lock() {
    sync.lock();
}

思考:但是在NonfairSync只看到了加锁方法,解锁方法在哪呢? 解锁的方法在父类Sync中

public void unlock() {
        sync.release(1);
    }

release方法来自AbstractQueuedSynchronizer#release

public final boolean release(int arg) {
    if (tryRelease(arg)) {
        Node h = head;
        if (h != null && h.waitStatus != 0)
            unparkSuccessor(h);
        return true;
    }
    return false;
}

ReentrantLock.Sync#tryRelease

一看就是典型的模板模式

protected final boolean tryRelease(int releases) {
    int c = getState() - releases;
    if (Thread.currentThread() != getExclusiveOwnerThread())
        throw new IllegalMonitorStateException();
    boolean free = false;
    if (c == 0) {
        free = true;
        setExclusiveOwnerThread(null);
    }
    setState(c);
    return free;
}

但是为什么要这么实现呢?

个人猜测是因为公平锁和非公平锁的加锁的流程是不同的,所以需要把加锁代码分别写在2个实现类里。

但是对于解锁来说,不管是公平锁还是非公平锁,流程是一样的,所以这部分逻辑可以抽取出来放到父类Sync中。

FairSync

static final class FairSync extends Sync {
        private static final long serialVersionUID = -3000897897090466540L;
        //加锁方法
        final void lock() {
            acquire(1);
        }
    
        //尝试加锁
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            //如果当前没人加锁 并且不需要排队 才会加锁
            if (c == 0) {
                if (!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;
        }
    }

genjiejie.blog.csdn.net/article/det…