ReentrantLock 独占锁学习

ReentrantLock

ReentrantLock 是可重入的独占锁 , 同 时 只能有 一个线程可 以 获取该锁,其他获取该锁
的线程会被阻塞而被放入该锁的 AQS 阻塞队列里面
在这里插入图片描述
ReentrantLock 最终还是使用 AQS 来实现的,并且根据参数来决定
其 内 部是一个公平还是非公平锁,默认是非公平锁

    public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

默认是非公平锁
其中 Sync 类直接继承自 AQS , 它的子类 NonfairSync 和 FairSync 分别实现了获取锁
的非公平与公平策略
AQS 的 state 状态值表示线程获取该锁的可重入次数 , 在默认情况下, state
的值为 0 表示当前锁没有被任何线程持有 。 当一个线程第一次获取该锁时会尝试使用 CAS
设置 state 的值为 l ,如果 CAS 成功则当前线程获取了该锁,然后记录该锁的持有者为当
前线程 。 在该线程没有释放锁的情况下第二次获取该锁后 ,状态值被设置为 2 , 这就是可
重入次数 。 在该线程释放该锁时,会尝试使用 CAS 让状态值减 1 , 如果减 l 后状态值为 o,
则 当前线程释放该锁 。

非公平锁 获取锁的过程

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

当一个线程调用该方法时 ,说明该线程希望获取该锁 。 如果锁当前没有被其他线程占
用并且当前线程之前没有获取过该锁,则当前线程会获取到该锁,然后设置当前锁的拥有
者为当前线程 , 并设置 AQS 的状态值为 1,然后直接返回 。 如果当前线程之前己经获取
过该锁,则这次只是简单地把 AQS 的状态值加 1后返回。如果该锁己经被其他线程持有,
则调用 该方法的线程会被放入 AQS 队列后阻塞挂起
ReentrantLock 的 lock()委托给了 sync 类,根据创建 ReentrantLock 构
造函数选择 sync 的实现是 NonfairSync 还是 FairSync,这个锁是一个非公平锁或者公平锁 。
这里看 sync 的子类 NonfairSync 的情况


    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() {
        	 //1) CAS设置状态值1
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
            //2) 调用 AQS 的 acquire方法
                acquire(1);
        }

        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
  1. 因为默认 AQS 的状态值为 0,所以 第一个调用 Lock 的线
    程会通过 CAS 设置状态值为 1, CAS 成功则 表示当前线程获取 到了锁, 然后
    setExclusiveOwnerThread 设置该锁持有者是当前线程
  2. 如果这时候有其他线程调用 lock 方法企图获取该锁, CAS 会失败,然后会调用 AQS
    的 acquire 方法 。注意 ,传递参数为 1
  • acquire代码
 public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

AQS 并没有提供可用的 tryAcquire 方法 , tryAcquire 方法需要子类自己定
制化,所以这里代码( 3 )会调用 ReentrantLock 重写 的 可Acquire 方法

   protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
  • nonfairTryAcquire
 final boolean nonfairTryAcquire(int acquires) {
 //获取当前线程
            final Thread current = Thread.currentThread();
            //获取state的值
            int c = getState();
            //如果是0
            if (c == 0) {
            //设置为1
                if (compareAndSetState(0, acquires)) {
                //设置独占的线程为当前线程
                    setExclusiveOwnerThread(current);
                    //返回成功
                    return true;
                }
            }
            //c!=0,并且,当前线程就是获取到锁的线程
            else if (current == getExclusiveOwnerThread()) {
            //state的值加1  acquires=1
                int nextc = c + acquires;
                //如果next的值小0 可重入次数溢出了
                if (nextc < 0) // overflow
                    throw new Error("Maximum lock count exceeded");
                    //设置state的值
                setState(nextc);
                //返回重入锁成功
                return true;
            }
           //如果当前线程不是锁的持有者则返回 false,然后其会被放入 AQS 阻塞队列。
            return false;
        }
公平锁
    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();
            //获取state状态
            int c = getState();
            //判断是0
            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() {
        // The correctness of this depends on head being initialized
        // before tail and on head.next being accurate if the current
        // thread is first in queue.
        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());
    }

如果当前线程节点有前驱节点则返回true, 否则如果当前 AQS 队列为空或者当前线程节点是 AQS 的第一个节点则返回 false。
其中如果 h==t 则说明当前队列为空 ,直接返回 false ;如果 h!=t 并且 s==null 则说明有一个元素将要作为 AQS 的第一个节点入队列 
( enq 函数的第一个元素入队列是两步操作: 首先创建一个哨兵头节点,然后将第一个元素插入哨兵节点后面 〉,
那么返回 true,如果 h!=t 并且 s!=null和 s.thr巳ad != Thread.cunentThread()
则说明队列里面的第一个元素不是当前线程,那么返回 true 。
释放锁
 public void unlock() {
        sync.release(1);
    }
最后看下 Sync 的实现
abstract static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = -5179523762034025860L;

        /**
         * Performs {@link Lock#lock}. The main reason for subclassing
         * is to allow fast path for nonfair version.
         */
        abstract void 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;
        }
		//释放锁
        protected final boolean tryRelease(int releases) {
        //获取当前state并减1
            int c = getState() - releases;
            //判断获取锁的线程是不是当前线程
            if (Thread.currentThread() != getExclusiveOwnerThread())
            //不是就抛出异常
                throw new IllegalMonitorStateException();
            boolean free = false;
            //如果减去 1后当前状态值为 0,则 当前线程会释放该锁 
            if (c == 0) {
           //设置标志为true成功
                free = true;
                //设置获取锁的线程为null
                setExclusiveOwnerThread(null);
            }
            //设置state的值
            setState(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() {
            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
        }
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值