java多线程juc中ReentrantLock 源码分析

2 篇文章 0 订阅
1 篇文章 0 订阅

ReentrantLock 源码分析

ReentrantLock(重入互斥锁)

public class LockDemo {

    static final Lock lock = new ReentrantLock();
    public static void main(String[] args) {
        lock.lock();
        //业务逻辑
        lock.unlock();
    }
}

分析之前首先了解一下Node

Node为双向列表 head指向头部 tail 指向尾部 pre 上一个线程 next 下一个线程 SHARED 共享锁 EXCLUSIVE独占锁

步骤分析

lock
  1. 调用ReentrantLock.lock()方法

    实际调用的是Sync的lock方法

public void lock() {
        sync.lock();
    }
  1. sync.lock()方法
  • sync.lock()其实是调用Sync的实现类NonfairSync(非公平锁)和FairSync(公平锁)

以非公平锁为例

 /**
     * Sync object for non-fair locks
     */
    static final class NonfairSync extends Sync {
        private static final long serialVersionUID = 7316153563782823691L;

        /**
         * Performs lock.  Try immediate barge, backing up to normal
         * acquire on failure.
         */
         //这里是Sync.lock();
        final void lock() {
            if (compareAndSetState(0, 1))
            //3.将当前线程设置为独占
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

        //5. 尝试获取锁
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
  1. compareAndSetState(0, 1)
  • 采用CAS判断当前线程锁状态是否可用

预期值为0 修改成1(如果偏移量不为0则返回false否则返回true)

  1. acquire(1); 获得锁方法 (以下方法都是抢锁状态)
  • 调用Sync父类AbstractQueuedSynchronizer 中的 acquire(int arg)
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  1. NonfairSync.tryAcquire(acquires) 尝试获取锁
  2. Sync.nonfairTryAcquire()
 /**
  * Performs non-fair tryLock.  tryAcquire is implemented in
  * subclasses, but both need nonfair try for trylock method.
  */
 final boolean nonfairTryAcquire(int acquires) {
 //获得当前线程
     final Thread current = Thread.currentThread();
     //获取当前线程starte偏移量
     int c = getState();
     if (c == 0) {
     //如果等于0说明当前当前锁对象已被释放
         if (compareAndSetState(0, acquires)) {
            //CAS成功后 将当前线程设置为独占锁(当前拿到锁)
             setExclusiveOwnerThread(current);
             return true;
         }
     }
     //不等于0时说明此对象已经有其他线程拿到锁
     else if (current == getExclusiveOwnerThread()) {
     //如果拿到锁的线程和当前线程相等,说明是同一线程,增加偏移量(重入锁)
         int nextc = c + acquires;
         if (nextc < 0) // overflow
             throw new Error("Maximum lock count exceeded");
             //将增加后的state存储
         setState(nextc);
         return true;
     }
     return false;
 }
  1. 看到这里让我们回顾之前获得锁的方法
public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
        //addWaiter()为当前线程增加节点
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }
  1. addWaiter(Node.EXCLUSIVE)
    /**
     * Creates and enqueues node for current thread and given mode.
     *
     * @param mode Node.EXCLUSIVE for exclusive, Node.SHARED for shared
     * @return the new node
     */
    private Node addWaiter(Node mode) {
    //创建node节点 此时mode=null
    //构造方法为:
    //Node(Thread thread, Node mode) {     // Used by addWaiter
    //   this.nextWaiter = mode;
    //   this.thread = thread;
    //}
        Node node = new Node(Thread.currentThread(), mode);
        // Try the fast path of enq; backup to full enq on failure
        //此时为tail==null pred==null  大于第二个线程则不会为null 后面会有说明
        Node pred = tail;
        if (pred != null) {
            node.prev = pred;
            //再次做CAS
            if (compareAndSetTail(pred, node)) {
                pred.next = node;
                return node;
            }
        }
        //enq只会执行一次  因为后续的抢占pred都不会为null 后续会有说明
        enq(node);
        return node;
    }
  1. enq(node)
    /**
     * Inserts node into queue, initializing if necessary. See picture above.
     * @param node the node to insert
     * @return node's predecessor
     */
    private Node enq(final Node node) {
        for (;;) {
            //tail为null  t==null
            Node t = tail;
            if (t == null) { // Must initialize
            //compareAndSetHead(new Node()): head初始化
                if (compareAndSetHead(new Node()))
                //第一遍循环肯定执行赋值操作  此时 head 和 tail 都已经被赋值为new Node()
                    tail = head;
            } else {
            //循环第二次的时候回走此方法 因T以被赋值
                node.prev = t; //将t赋值给prev
                if (compareAndSetTail(t, node)) {
                    //将当前node节点赋值给next
                    t.next = node;
                    return t;
                }
            }
        }
    }
  1. acquireQueued(addWaiter(Node.EXCLUSIVE), arg));
    /**
     * Acquires in exclusive uninterruptible mode for thread already in
     * queue. Used by condition wait methods as well as acquire.
     *
     * @param node the node
     * @param arg the acquire argument
     * @return {@code true} if interrupted while waiting
     */
    final boolean acquireQueued(final Node node, int arg) {
        boolean failed = true;
        try {
            //阻断默认为false
            boolean interrupted = false;
            for (;;) {
                //获取上一个节点
                final Node p = node.predecessor();
                //再次尝试抢占锁
                if (p == head && tryAcquire(arg)) {
                    //如果抢占成功 1.将当前node设置为头节点 2.将thread设置为null 3.将prev设置为null
                    setHead(node);
                    //将上一个节点的下一个节点设置为null
                    p.next = null; // help GC
                    failed = false;
                    return interrupted;
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    //线程恢复后,如果当前线程被中端过,interrupted为true
                    interrupted = true;
            }
        } finally {
            if (failed)
                //清除无用节点(waitStatus为CANCELLED)
                cancelAcquire(node);
        }
    }
  1. shouldParkAfterFailedAcquire(Node pred, Node node)
    /**
     * Checks and updates status for a node that failed to acquire.
     * Returns true if thread should block. This is the main signal
     * control in all acquire loops.  Requires that pred == node.prev.
     *
     * @param pred node's predecessor holding status
     * @param node the node
     * @return {@code true} if thread should block
     */
    private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
        //判断上一节点的waitStatus
        int ws = pred.waitStatus;
        if (ws == Node.SIGNAL)
        //锁状态直接返回true
            /*
             * This node has already set status asking a release
             * to signal it, so it can safely park.
             */
            return true;
        if (ws > 0) {
            //大于0需要清除出现错误的节点  也就是状态为:CANCELLED
            /*
             * Predecessor was cancelled. Skip over predecessors and
             * indicate retry.
             */
            do {
                node.prev = pred = pred.prev;
            } while (pred.waitStatus > 0);
            //设置当前节点为上一节点的下一个节点
            pred.next = node;
        } else {
            /*
             * waitStatus must be 0 or PROPAGATE.  Indicate that we
             * need a signal, but don't park yet.  Caller will need to
             * retry to make sure it cannot acquire before parking.
             */
             //上一节点的waitStatus小于0 则将上一个节点的waitStatus设置为SIGNAL(-1)
            compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
        }
        return false;
    }
  1. 如果shouldParkAfterFailedAcquire为true则执行parkAndCheckInterrupt())
  • 阻塞 调用LockSupport.park(this) 将当前线程挂起
/**
     * Convenience method to park and then check if interrupted
     *
     * @return {@code true} if interrupted
     */
    private final boolean parkAndCheckInterrupt() {
        LockSupport.park(this);//挂起
        //获得当前线程是否被中段过(在此线程被唤醒时会接着从这里执行)
        return Thread.interrupted();
    }

13.在这里回顾一下acquire方法,将以上步骤串联起来

  public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            //进入如果说明tryAcquire(arg)==false acquireQueued==true
            //说明有其他线程在此线程挂起后发起过中断操作,这里此线程已被唤醒,需要响应中断操作
            selfInterrupt();
    }

14.selfInterrupt();

    /**
     * Convenience method to interrupt current thread.
     */
    static void selfInterrupt() {
        Thread.currentThread().interrupt();
    }
unlock
  1. ReentrantLock.lock();
public void unlock() {
        sync.release(1);
    }

2.release(1) 释放锁

AbstractQueuedSynchronizer工具包中的方法

    /**
     * Releases in exclusive mode.  Implemented by unblocking one or
     * more threads if {@link #tryRelease} returns true.
     * This method can be used to implement method {@link Lock#unlock}.
     *
     * @param arg the release argument.  This value is conveyed to
     *        {@link #tryRelease} but is otherwise uninterpreted and
     *        can represent anything you like.
     * @return the value returned from {@link #tryRelease}
     */
    public final boolean release(int arg) {
        //尝试释放锁
        if (tryRelease(arg)) {
            Node h = head;
            if (h != null && h.waitStatus != 0)
                //如果当前头部节点不为null 并且 状态不为0
                unparkSuccessor(h);
            return true;
        }
        return false;
    }

3.tryRelease(arg)

 protected final boolean tryRelease(int releases) {
    //重入锁次数减1
     int c = getState() - releases;
     if (Thread.currentThread() != getExclusiveOwnerThread())
         throw new IllegalMonitorStateException();
     boolean free = false;
     if (c == 0) {
     //如果state==0时,说明当前无线程抢占
         free = true;
         setExclusiveOwnerThread(null);
     }
     //设置为getState() - releases的值
     setState(c);
     return free;
 }

4.unparkSuccessor(h);唤醒线程 和 lock中的park相互呼应

    /**
     * Wakes up node's successor, if one exists.
     *
     * @param node the node
     */
    private void unparkSuccessor(Node node) {
        /*
         * If status is negative (i.e., possibly needing signal) try
         * to clear in anticipation of signalling.  It is OK if this
         * fails or if status is changed by waiting thread.
         */
        int ws = node.waitStatus;
        if (ws < 0)
            //原子操作将当前线程状态设置为0
            compareAndSetWaitStatus(node, ws, 0);

        /*
         * Thread to unpark is held in successor, which is normally
         * just the next node.  But if cancelled or apparently null,
         * traverse backwards from tail to find the actual
         * non-cancelled successor.
         */
        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)
            //唤醒线程对应着lock中park阻塞线程
            LockSupport.unpark(s.thread);
    }

非公平锁和公平锁的区别

  1. lock()方法

    • 非公平锁
    final void lock() {
        //这里直接插队
        if (compareAndSetState(0, 1))
            setExclusiveOwnerThread(Thread.currentThread());
        else
            acquire(1);
    }
    
    • 公平锁
    final void lock() {
            acquire(1);
        }
    
  2. lock()方法

    • 非公平锁
        /**
         * Performs non-fair tryLock.  tryAcquire is implemented in
         * subclasses, but both need nonfair try for trylock method.
         */
        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;
        }
    
    • 公平锁
        /**
         * Fair version of tryAcquire.  Don't grant access unless
         * recursive call or no waiters or is first.
         */
        protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
            if (c == 0) {
                //这里会有一层判断 
                //h != t &&((s = h.next) == null || s.thread != Thread.currentThread());
                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;
        }
    
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猿道apeto

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值