ReentrantLock-可重入锁

1.下面先分析一下ReentrantLock类

private final Sync sync;

ReentrantLock持有了sync变量,Sync类下面有FairSync和NonfairSync,也就是通常所说的公平锁和非公平锁。

2.构造方法

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

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

调用构造方法创建锁时,默认创建非公平锁,也可以传入boolean参数选择创建公平锁或非公平锁。

3.成员方法

    //调用具体公平锁/非公平锁的lock方法获取锁,获取失败会进入等待队列等待
    public void lock() {
        sync.lock();
    }
    //同上也是获取锁的方法,会检查当前线程是否被中断,如果中断会抛InterruptedException异常
    public void lockInterruptibly() throws InterruptedException {
        sync.acquireInterruptibly(1);
    }
    //非公平获取锁,也就是通过cas直接去争抢锁,争抢失败则返回false,只争抢一次
    public boolean tryLock() {
        return sync.nonfairTryAcquire(1);
    }
    //带超时的获取锁的方法,线程会阻塞进入等待队列,如果时间超时则取消等待
    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();
    }
    //获取重入次数,返回的是state状态的值,state表示锁每被获取一次,值+1,为0表示锁未被获取
    public int getHoldCount() {
        return sync.getHoldCount();
    }
    //锁是否被当前线程持有
    public boolean isHeldByCurrentThread() {
        return sync.isHeldExclusively();
    }
    //锁是否被占用,判断state是否=0
    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);
    }

4.ReentrantLock.tryLock方法

    public boolean tryLock(long timeout, TimeUnit unit)
            throws InterruptedException {
        return sync.tryAcquireNanos(1, unit.toNanos(timeout));
    }

    //AQS中的方法,先是调用tryAcquire尝试获取锁,如果锁被占用获取失败则再调用doAcquireNanos
    //arg参数为1,表示获取锁成功后将独占锁的状态加1
    
    public final boolean tryAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        return tryAcquire(arg) ||
            doAcquireNanos(arg, nanosTimeout);
    }
//****FairSync的tryAcquire****
    //从这里可以看出state的值如果大于0则说明被占用了,而这个值越大说明锁被重入的次数越多
    protected final boolean tryAcquire(int acquires) {
            final Thread current = Thread.currentThread();
            int c = getState();
    //1.如果锁的状态为0(锁空闲),则继续判断当前线程前面是否还有节点在排队;如果 
    //当前线程是第一个节点,那么CAS修改同步器状态为1(抢占锁);再设置当前线程为独占线程。
            if (c == 0) {
                if (!hasQueuedPredecessors() &&
                    compareAndSetState(0, acquires)) {
                    setExclusiveOwnerThread(current);
                    return true;
                }
            }
            //2.如果锁被当前线程占用,则说明是重入获取锁,将状态值进行增加。(从这里可以看出state的值等于锁被线程重入的次数)
            //如果增加后的值小于0了,说明获取锁的次数超出了int的上限,抛出次数上限的error。
            else if (current == getExclusiveOwnerThread()) {
                int nextc = c + acquires;
                if (nextc < 0)
                    throw new Error("Maximum lock count exceeded");
                setState(nextc);
                return true;
            }
            return false;
        }

//****AQS的doAcquireNanos方法****  超时获取不到锁则放弃获取,会判断线程中断
    private boolean doAcquireNanos(int arg, long nanosTimeout)
            throws InterruptedException {
        //如果获取时间小于等于0,那么说明已超时
        if (nanosTimeout <= 0L)
            return false;
        //获取最后超时时间
        final long deadline = System.nanoTime() + nanosTimeout;
        //入队一个当前线程的独占节点到等待队列的尾部
        final Node node = addWaiter(Node.EXCLUSIVE);
        //用于执行下面finally块的cancelAcquire方法释放节点
        boolean failed = true;
        try {
            for (;;) {
                //获取尾部节点的前继节点
                final Node p = node.predecessor();
                //如果前一个节点是头结点那么就尝试获取锁
                if (p == head && tryAcquire(arg)) {
                    //获取锁成功设置头节点为当前线程的节点
                    setHead(node);
                    //把原来的头节点的next置为空,用于GC
                    p.next = null; // help GC
                    //状态值改变,finally中不需要再释放节点
                    failed = false;
                    //返回获取锁成功
                    return true;
                }
                //用时间截止线-当前时间,判断获取时间是否超时,超时则自动返回获取锁失败
                nanosTimeout = deadline - System.nanoTime();
                if (nanosTimeout <= 0L)
                    return false;
                //判断该节点的线程获取锁失败后,是否需要休息(进入waiting状态),如果是,则再判断剩余超时时间是否充足(大于spinForTimeoutThreshold),如果上述两个条件都满足则让当前线程进入waiting状态,等待唤醒
                if (shouldParkAfterFailedAcquire(p, node) &&
                    nanosTimeout > spinForTimeoutThreshold)
                    LockSupport.parkNanos(this, nanosTimeout);
                if (Thread.interrupted())
                    throw new InterruptedException();
            }
        } finally {
            if (failed)
                cancelAcquire(node);
        }
    }

上面是公平锁的获取锁代码, 可以看出公平锁是每一次只能头结点的后继节点才能有资格获取锁,获取锁通过cas完成。

而非公平锁是任何节点都会使用cas去抢占获取锁,没有先后顺序之分,可能先到的后获取到锁,也可能会一直等待(这称为线程饥饿)

    static final class NonfairSync extends Sync {
        final void lock() {
            //cas获取锁,把锁的状态从0修改成1,如果修改成功则说明抢占到锁的使用了,将锁的独占线程修改成当前线程
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
            //如果抢占失败则调用acquire方法再次获取,并进入阻塞
                acquire(1);
        }
        //调用非公平获取锁方法
        protected final boolean tryAcquire(int acquires) {
            return nonfairTryAcquire(acquires);
        }
    }
    //1.先调用tryAcquire方法尝试获取锁,这里调用的就是上面非公平锁重写的nonfairTryAcquire方法
    //2.如果尝试获取锁失败,那么则添加当前线程到等待队列尾部,进入waiting状态
    //3.进入中断状态
    public final void acquire(int arg) {
        if (!tryAcquire(arg) &&
            acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
            selfInterrupt();
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值