当前位置: 首页 > article >正文

AQS之ReentrantLock独占锁源码解析

 一、基础概念

AQS(AbstractQueuedSynchronizer):是jdk并发包java.util.concurrent下绝大部分工具类实现的基础。

管程:是指管理共享变量以及对共享变量操作的过程,让它们支持并发

JVM层对管程的实现:synchronized

JAVA层对管程的实现:AQS抽象层,对AQS进行实现

JAVA的线程安全问题解决方案:cas+自旋(会出现空转cpu的问题)、synchronized、reentrantLock 会阻塞未获取锁的线程

----- JDK中提供的大多数的同步器如Lock,Latch,Barrier等,都是基于AQS框架来实现的,一般事通过一个内部类Sync继承AQS将同步器所有调用都映射到Sync对应的方法        

  二、AQS

特性:阻塞等待队列    共享/独占   公平/非公平  可重入  允许中断

 AQS内部维护属性 volatile int state

        表示同步的状态,对于独占锁而言,这个属性可以网上增加,每重入一次就+1;对于共享锁而言,就是资源个数,每来一个-1,当减为0以后,后续的资源就不能获取到锁了。

         state三种访问方式

        getState()  setState()  compareAndSetState()

AQS定义两种资源共享方式:

Exclusive 独占,只有一个线程能获取锁执行,如ReentrantLock

Share  共享 ,多个线程可以同时执行,如 Semaphore/CountDownLatch

AQS定义两种等待队列:

同步等待队列:主要用于维护获取锁失败时入队的线程

条件等待队列:调用await()的时候会释放锁,然后线程会加入到条件队列,调用signal()唤醒的时候会把条件队列中的线程节点移动到同步队列中,等待再次获得锁。

        不同的自定义同步器竞争共享资源的方式也不同。自定义同步器在实现时只需要实现共享 资源state的获取与释放方式即可,至于具体线程等待队列的维护(如获取资源失败入队/唤醒出队等),AQS已经在顶层实现好了。自定义同步器实现时主要实现以下几种方法:

  1. isHeldExclusively():该线程是否正在独占资源。只有用到condition才需要去实现它

tryAcquire(int):独占方式。尝试获取资源,成功则返回true,失败则返回false。

tryRelease(int):独占方式。尝试释放资源,成功则返回true,失败则返回false。

tryAcquireShared(int):共享方式。尝试获取资源。负数表示失败;0表示成功,但没有剩余可用资源;正数表示成功,且有剩余资源。

tryReleaseShared(int):共享方式。尝试释放资源,如果释放后允许唤醒后续等待结点返回true,否则返回false。

 同步等待队列 (双向链表结构)

        基于双向链表数据结构的队列是FIFO先进先出线程等待队列

 条件等待队列

        AQS中条件队列是使用单向列表保存的,用nextWaiter来连接: 调用await方法阻塞线程;

当前线程存在于同步队列的头结点,调用await方法进行阻塞(从同步队列转化到条 件队列

自定义实现AQS:

实现加锁 解锁逻辑

public class MyselfLock extends AbstractQueuedSynchronizer {

    @Override
    protected boolean tryAcquire(int unused) {
        //cas 实现加锁逻辑 默认 state =0 ,
        if(compareAndSetState(0,1)){
            //将当前的线程进行绑定,设置为一个独占的线程
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    @Override
    protected boolean tryRelease(int unused) {
        //释放锁
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }
    public void lock(){
        acquire(1);
    }
    public boolean tryLock(){
        return tryAcquire(1);
    }
    public void unlock(){
        release(1);
    }


http://www.kler.cn/a/6887.html

相关文章:

  • 【经验分享】2024年11月下半年软件设计师考试选择题估分(持续更新~~)
  • 使用 GoZero 实现读取绩效表格 Excel 并打分
  • 游戏引擎学习第12天
  • DNS with libevent
  • MySQL45讲 第二十四讲 MySQL是怎么保证主备一致的?——阅读总结
  • Django5 2024全栈开发指南(三):数据库模型与ORM操作
  • top 输出中涉及到的一些参数的解释
  • SonarQube安装教程
  • 2023年noc指导教师认证测评参考试题
  • 重学Java设计模式-结构型模式-代理模式
  • Vue3通透教程【十一】初探TypeScript
  • 离散制造企业数字化转型难点问题
  • 【C++从0到1】7.C++中标识符的命名
  • 蓝桥杯刷题冲刺 | 倒计时4天
  • 【QsLog动态库的编译和使用】
  • 【Git】版本控制之基础用法
  • 如何低成本实现微前端架构?
  • arm-himix100-linux-gcc no such file or directory 解决办法
  • 华为OD机试用JS实现 -【查找树中的元素 or 查找二叉树节点】(2023-Q2 押题)
  • 1-ELK+ Elasticsearch+head+kibana、企业内部日志分析系统
  • Android列表实现单选、多选、全选、取消、删除
  • kubernetes各个条件下使用nginx-ingress进行路由映射
  • git 删除提交记录
  • flex布局:输入框布局demo
  • 多国拟发ChatGPT禁令 关“野兽”的笼子要来了?
  • itop-3568开发板驱动学习笔记(8)高级字符设备(二)IO 多路复用