c++ 底层获取机器码_Lock底层原理—ReentrantLock、AQS、Condition

Lock底层原理—ReentrantLock、AQS、Condition先来看看J.U.C包下的结构juc-locks 锁框架juc-atomic 原子类框架juc-sync 同步器框架juc-collections 集合框架juc-executors 执行器框架而我们今天的主角ReentrantLock,就是juc-locks包下的。上一篇刚算了解一下synchronized的底层原理,所以就想...
摘要由CSDN通过智能技术生成

Lock底层原理—ReentrantLock、AQS、Condition

先来看看J.U.C包下的结构

  • juc-locks 锁框架
  • juc-atomic 原子类框架
  • juc-sync 同步器框架
  • juc-collections 集合框架
  • juc-executors 执行器框架

而我们今天的主角ReentrantLock,就是juc-locks包下的。上一篇刚算了解一下synchronized的底层原理,所以就想看看ReentrantLock和它的区别到底是什么,改进在哪里,适用于什么场景。

1. Lock

LockReadWriteLock是两大锁的根接口,下面看一下JDK 1.8 API中如何描述的

224200f3453df06f69dbde9cef72b00a.png

通过API的介绍,sychronizedLock的区别可以分为如下:

  • Lock增加了灵活性,最主要的就是支持多个Condition。
  • Lock提供了非阻塞获得锁的方式,synchronized有自旋锁。
  • Lock更适合使用在复杂的同步,而synchronized更简单、简杰。
  • Lock 可以设置公平锁和非公平锁,synchronized只有非公平锁。

浏览一下Lock 源码

package java.util.concurrent.locks;

import java.util.concurrent.TimeUnit;

public interface Lock {
    
    //获得锁
    void lock();
    //获取锁定,除非当前线程中断
    void lockInterruptibly() throws InterruptedException;
    //只有在调用时才可以获得锁
    boolean tryLock();
    //如果在给定的等待时间内是空闲的,并且当前的线程尚未得到 interrupted,则获取该锁
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    //释放锁。
    void unlock();
    //返回一个新Condition绑定到该实例Lock实例
    Condition newCondition();
}

2. ReentrantLock

Lock了解之后,看一下实现类是如何实现接口的方法的。最常用的实现类就是ReentrantLock

2.1. 公平锁和非公平锁

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

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

从构造函数上可以看出来ReentrantLock实现了公平锁和非公平锁两种,默认一般使用非公平锁,它的效率和吞吐量都比公平锁高的多。

2.2. Sync

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

2.3. NonfairSync

非公平锁实现

static final class NonfairSync extends Sync {
    
        private static final long serialVersionUID = 7316153563782823691L;

        final void lock() {
    
            /**
             * 先抢锁
             */
            if (compareAndSetState(0, 1))
                setExclusiveOwnerThread(Thread.currentThread());
            else
                acquire(1);
        }

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

2.4. FairSync

说完了非公平锁,那就不得不提公平锁的实现了。

static final class FairSync extends Sync {
    
        private static final long serialVersionUID = -3000897897090466540L;

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

        //非公平锁调用的是父类sync的nonfairTryAcquire方法
        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;
        }
    }

有了非公平锁做铺垫,了解公平锁就方便多了。公平锁和非公平锁不同之处在于,公平锁在获取锁的时候,不会先去检查state状态。

公平锁和非公平锁最主要的区别在于lock(),一个是先排队,一个是先抢锁。但是非公平锁的吞吐量更大。

通过查看ReentrantLock中的底层实现,我们发现了AQS的踪迹,先看一下AQS是什么,然后分析一下整个锁的流程。

3. AbtractQueuedSynchronizer

AbtractQueuedSynchronizer抽象的队列式的同步器,AQS定义了一套多线程访问共享资源的同步器框架,是JUC包下整体的基础框架。AQS是一个抽象的队列同步器,维护着一个同步队列和State状态 。底层使用了Unsafe类进行CAS操作。Sync就是AbstractQueuedSynchronizer的子类,AQS采用了模板方法模式,提高了扩展性有保证了规范性。

AQS只是一个框架,具体资源的获取/释放方式交由自定义同步器去实现

JDK 1.8 API中的介绍如下

25d8e3092732ed50e4411f41d7d2c995.png

从上述介绍中可以看出:

  • 同步器依赖于每个Node的状态,状态都是通过CAS来设置的。
  • AQS支持独占模式共享模式

还有一些关于Condition,下面再去研究。

看一下其内部图片:

b2e254d2a515d8003b5917d8cf5efecc.png
AbtractQueuedSynchronizer 内部维持着一个 虚拟的双向同步队列,因为队列中只有头节点和尾节点的指针。

Node是AQS中的节点类

/** Marker to i
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值