ReentrantLock 源码解析(一)—— AQS到底是什么

之前写了一篇剖析ReentrantLock源码的文章(超详细的源码分析)。

有反馈说,写的太长了!我也觉得写的很长,那就重新发一次,拆分版的。

前言

ReentrantLock 是基于 AQS 框架实现,JDK 中线程并发访问的同步技术,

它是一个互斥锁,也叫独占锁,支持可重入,支持锁的公平性。

大神Doug Lea写的,整个AQS框架都是他一个人撸出来的,牛!

Doug Lea有多牛

就像:

  • 谈喜剧电影,不可能不提星爷
  • 谈相声,绕不开郭德钢
  • 说中国教育,总得聊聊蔡元培
  • 说到心理学,一定得说弗洛伊德
  • 说到并发编程,Doug Lea不得不提

java1.6 之前, synchronized效率太低了,大神Doug Lea就开发了AQS框架,就是解决并发问题。

JDK的出品公司SUN公司,一看,呀,这AQS性能那是相当可以,好吧,那就吸收进来,直接放JDK里吧。

synchronized可是SUN公司亲生的呀,可性能太差,SUN公司琢磨,要不优化下synchronized

于是乎,SUN公司的开发团队,历经数年,优化了synchronized,其性能大大提升,和AQS不相上下了。

从某种程度上说,Doug Lea 以一已之力,PK SUN公司整个开发团队,牛人!

这里从ReentrantLock 加锁解锁机制,由浅入深,让你彻底弄懂其原理。

一、应用场景

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(1);
        for(int i = 0; i < 10; i++){
            new Thread(() -> {
                try {
                    downLatch.await();
                    for(int j = 0; j < 1000; j++){
                        total++;
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(2000);
        downLatch.countDown();
        Thread.sleep(2000);
        System.out.println(total);
    }

这段代码,起10个线程,每个线程加 1000 次,期望值是 10000,但因为并发,最后会小于 10000


    public static void main(String[] args) throws InterruptedException {
        CountDownLatch downLatch = new CountDownLatch(1);
        ReentrantLock lock = new ReentrantLock();
        for(int i = 0; i < 10; i++){
            new Thread(() -> {
                try {
                    downLatch.await();
                    lock.lock(); // 加锁
                    for(int j = 0; j < 1000; j++){
                        total++;
                    }
                    lock.unlock(); // 解锁
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
        Thread.sleep(2000);
        downLatch.countDown();
        Thread.sleep(2000);
        System.out.println(total);
    }

控制了并发访问,算出来的结果就是 10000

二、什么是AQS

简单讲,AQS(AbstractQueuedSynchronizer),是大神Doug Lea写的,一个同步框架。

JDK 中 java.util.concurrent 包下,很多处理并发的工具类都直接或间接引用了AQS,比如ReentrantLock,Semaphore,CountDownLatch……

在这里插入图片描述
AQS 这个抽象类中,有几个重要属性,咱先放在前面说一下。

  • 首先说下,AQS 里面的内部类Node的几个属性

volatile int waitStatus;  // Node里,记录状态用的

volatile Thread thread;  // Node里,标识哪个线程

volatile Node prev;  // 前驱节点(这个Node的上一个是谁)

volatile Node next; // 后继节点(这个Node的个一个是谁)
  • AQS 本身的属性

private transient Thread exclusiveOwnerThread; // 标识拿到锁的是哪个线程

private transient volatile Node head; // 标识头节点

private transient volatile Node tail; // 标识尾节点

private volatile int state; // 同步状态,为0时,说明可以抢锁

这里画了张图,很直观,咱们照着图来说

在这里插入图片描述
当多个线程来竞争锁的时候,若抢锁失败,则生成一个Node,与 Thread 绑定,进入队列,该线程就被阻塞。

当锁释放时,唤醒节点去抢锁。

这个由Node对象组成的队列,叫CLH队列,是一个先进先出的队列,双向指针。

下篇: ReentrantLock 加锁 解锁 方法概览

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值