ReentrantLock源码分析

165 阅读3分钟

ReentrantLock支持非公平锁和公平锁,通过构造器中的参数来选择,默认为非公平锁。

非公平锁

lock()源码分析

     final void lock() {
        if (compareAndSetState(0, 1)) //设置state为1,多线程时候仅会有一个线程成功
             setExclusiveOwnerThread(Thread.currentThread());//将获取到锁的线程存储起来
             //后续实现可重入功能的时候要使用
        else  //其它未设置成功的线程走这里
             acquire(1);
     }

acquire

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  1. tryAcquire()用于获取锁,获取到则返回true;否则,返回false
  2. addWaiter()用于在链表尾部添加线程节点,添加成功则返回true;否则,返回false
  3. acquireQueued()用于阻塞线程

如果获取到锁,则返回;未获取到锁,则添加线程节点到队列的尾部,并且再次查看当前节点是否能获取到锁,如果能获取到,则返回;如果再次获取无法获取到,则进入阻塞,等待被唤醒

tryAcquire

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }

        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);//可重入通过新增state的值去实现
                return true;
            }
            return false;
        }

addWaiter

    private Node addWaiter(Node mode) {
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        Node pred = tail;
        if (pred != null) {//快速添加到队列尾
            node.prev = pred;
            //只有一个线程能添加成功,其它线程无法添加,走full enq
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        enq(node);//如果pred为null 或者 其它调compareAndSetTail无法成功 这两种情况的线程会执行
        return node;
    }

    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;
                if (compareAndSetTail(t, node)) {//无限循环+该行 = CAS
                    t.next = node;
                    return t;
                }
            }
        }
    }

acquireQueued

    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            boolean interrupted = false;
            //大部分获取不到锁,就进入阻塞并等待unpark,unpark后又开始循环,
            //并重新尝试获取锁,如果获取到了就返回,否则,获取不到就再次进入阻塞
            for (;;) {//死循环,最终节点一定会进入阻塞 或者 获取到了锁
                final Node p = node.predecessor();//想一想为什么是判断前一个节点是否为头结点。
//原因见enq方法,针对一个空队列,头结点是空节点
                if (p == head && tryAcquire(arg)) {
                    setHead(node); //获取到锁后,将当前节点设置为头结点
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    interrupted = true;
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

waitStatus

/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED =  1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL    = -1;
/** waitStatus value to indicate thread is waiting on condition */
static final int CONDITION = -2;
/** waitStatus value to indicate the next acquireShared should unconditionally propagate */
static final int PROPAGATE = -3;

shouldParkAfterFailedAcquire

    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
            //前置节点已经设置了要求释放信号的状态,所以它可以安全停车
            return true;
        if (ws > 0) {
            //前置节点是取消状态,从后往前跳过所有状态为取消状态的节点,直到碰到第一次非取消的状态
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            pred.next = node;
        } else {
            //waitStatus必须为0或PROPAGATE。暗示我们需要信号,但先别停车。呼叫者将需要重试,
            //以确保在停车前它不能获得。
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }

parkAndCheckInterrupt

    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);//阻塞当前线程,等待unpark
        return Thread.interrupted();
    }

unlock()源码分析

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

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;
    }

tryRelease

        protected final boolean tryRelease(int releases) {
            int c = getState() - releases;
            if (Thread.currentThread() != getExclusiveOwnerThread())
                throw new IllegalMonitorStateException();
            boolean free = false;
            if (c == 0) {//只有完全释放了即state=0返回true;释放重入计数,即state!=0返回false
                free = true;
                setExclusiveOwnerThread(null);
            }
            setState(c);
            return free;
        }

unparkSuccessor

    private void unparkSuccessor(Node node) {
        int ws = node.waitStatus;
        if (ws < 0) //节点状态小于0,设置为0
            compareAndSetWaitStatus(node, ws, 0);
        //找到队列最靠前的状态小于0的节点
        Node s = node.next;
        if (s == null || s.waitStatus > 0) {
            s = null;
            for (Node t = tail; t != null && t != node; t = t.prev)
                if (t.waitStatus <= 0)
                    s = t;
        }
        //如果找到了符合状态的节点,就唤醒它
        if (s != null)
            LockSupport.unpark(s.thread);
    }

思考一个问题

为什么是非公平锁?哪里体现了非公平?

通过上面分析

  1. 公平:先来的线程应该先获取到锁,后面的后获取到锁;非公平:后来的线程可以先于先来的线程获取到锁。

  2. 在进入阻塞队列之前有三次获取锁,分别在lock、tryAcquire、acquireQueued三个方法中,如果在放入阻塞队列之前,获取到锁,那么对于队列中的线程节点是不公平的;如果都获取不到,就会进入阻塞队列。

  3. 队列里面的等待的线程节点就是按照从队列头到队列尾的顺序(FIFO)依次获取锁的。

公平锁

lock()源码分析

  final void lock() {
      acquire(1);
  }

acquire 和非公平锁一样

    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

tryAcquire

        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;
        }
    }

hasQueuedPredecessors

   //先做一次判断该线程是否需要放入阻塞队列
   public final boolean hasQueuedPredecessors() {
        Node t = tail; // Read fields in reverse initialization order
        Node h = head;
        Node s;
        return h != t &&
            ((s = h.next) == null || s.thread != Thread.currentThread());
    }

unlock()源码分析

和非公平锁一样