IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 深入理解AQS之独占锁ReentrantLock源码分析 -> 正文阅读

[Java知识库]深入理解AQS之独占锁ReentrantLock源码分析

目录

1.java为什么要实现自己的管程机制?

2.AQS

?

2.1 state

?2.2 同步等待队列和条件等待队列

?2.3 自定义AQS

3.reentrantLock详解

3.1 源码分析(TODO)


1.java为什么要实现自己的管程机制?

管程:操作系统底层实现的对线程并发问题实现的监视器机制,管程内部大致分为:同步等待队列和等待唤醒队列。

同步等待队列的实现:synchronized在jvm底层保证线程能够串行化的操作同步代码块内的程序。

等待唤醒队列的实现:java在object类中实现了monitor机制,每个对象都有一个monitor,可以手动调用wait/notify/notifyall方法操作线程。

synchronized缺点:不能手动加锁解锁,synchronized内部加解锁是自动的。

为了解决以上场景java实现了自己的管程机制AQS机制:

同步等待队列(双向链表结构):cas实现(内部通过volatile int state状态控制入队出队) 加解锁有自己的实现

条件等待队列(单向链表结构):Condition接口实现(await/signal/signalAll等待;唤醒机制)

2.AQS

基于上述描述讲解AQS。

AQS的特性:

? ? ? ? 1. 阻塞等待队列

? ? ? ? 2. 共享/独占

? ? ? ? 3. 公平/非公平

? ? ? ? 4. 可重入

? ? ? ? 5. 允许中断

AQS的实现类如下图。

AQS的资源共享方式

????????独占:只有一个线程能执行,如reentrantLock

????????共享:多个线程同时执行,如Semaphore和CountDownLatch

AQS的两种队列:同步等待队列和条件等待队列

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

????????条件等待队列:调用await时会释放锁进入条件等待队列,调用signal时唤醒线程放入同步等待队列

AQS中实现的方法

????????共享:tryAcquireShared获取共享锁,releaseShared解锁,tryReleaseShared尝试解锁

????????独占:tryAcquire获取独占锁,release解锁,tryRelease尝试解锁

2.1 state

AQS中volatile int修饰的state:表示AQS的状态

state的访问方式:

getState(),setState(),compareAndSetState()

?

?2.2 同步等待队列和条件等待队列

同步等待队列是一个双向链表的队列。

条件等待队列是一个单向链表结构,条件调用await唤醒以后进入同步等待队列,同步等待队列阻塞进入条件等待队列。

?2.3 自定义AQS

自定义自己的AQS实现类:

1.继承AbstractQueuedSynchronizer

2.实现自己的抽象方法tryAcquire和tryRelease方法。其他方法都是AQS已经封装好的直接调用即可。

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class TestLock extends AbstractQueuedSynchronizer {

    private int state_0 = 0;//0-解锁
    private int state_1 = 1;//1-加锁

    //加锁逻辑:使用CAS实现,如果修改成功返回true并且设置独占锁,否则返回false
    @Override
    protected boolean tryAcquire(int arg) {
        if(compareAndSetState(state_0,arg)){
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    //释放锁:将锁状态还原
    @Override
    protected boolean tryRelease(int arg) {
        setExclusiveOwnerThread(null);
        setState(arg);
        return true;
    }

    public void lock(){
        acquire(state_1);
    }

    public boolean tryLock(){
        return tryAcquire(state_1);
    }

    public void unLock(){
        release(state_0);
    }

    public boolean tryUnLock(){
        return tryRelease(state_0);
    }
}

class TestAQS{
    private static int sum = 0;

    private static TestLock testLock = new TestLock();

    public static void main(String[] args) throws InterruptedException {
        for (int i =0 ;i<3;i++){
            Thread thread = new Thread(()->{
                testLock.lock();
                try{
                    for (int j=0;j<10000;j++){
                        sum++;
                    }
                }finally {
                    testLock.unLock();
                }

            });
            thread.start();
        }

        //休眠1秒等待线程执行完毕
        Thread.sleep(1000);
        System.out.println("sum:"+sum);
    }
}

3.reentrantLock详解

reentrantLock是一个基于AQS框架的锁,可以手动加解锁,比synchronized性能要好一点,支持解决并发安全问题,支持公平和非公平锁。

synchronized与reenTrantLock的区别:最重要的区别就是reenTrantLock需要在finally块中手动解锁。

reenTrantLock的特点:

? ? ? ? 1.可中断

? ? ? ? 2.可设置超时时间

? ? ? ? 3. 可以设置公平锁

? ? ? ? 4. 支持多个条件变量

? ? ? ? 5. 支持可重入

3.1 源码分析(TODO)

关注点:

1.加解锁

2.公平,非公平,可重入实现

3.线程竞争锁失败入队阻塞逻辑和获取锁的线程释放锁唤醒阻塞线程竞争锁的逻辑实现

重点debug下面代码:lock.lock和lock.unlock源码部分

1.lock.lock(加锁,默认非公平锁实现):CAS判断,如果修改成功,设置独占锁,没有走公平锁逻辑获取锁。

? ? ? ? 1.1 公平锁逻辑分为几步:

? ? ? ? ? ? ? ? 1.1.1 尝试获取锁(tryAcquire(int acquires)),分为两步:1.线程状态state为0执行CAS独占锁逻辑。2.如果当前线程是独占锁执行重入锁逻辑,将state加1。

? ? ? ? ? ? ? ? 1.1.2 入队(addWaiter(Node.EXCLUSIVE)),桟入队操作有点儿复杂(TODO),简单来说就是双向链表的建立过程。

? ? ? ? ? ? ? ? 1.1.3 获取队列(boolean acquireQueued(final Node node, int arg)),也是分为两步:1.如果是只有一个节点并且获取锁成功返回中断标志位为false;2.如果不是只有一个节点通过waitstatus标志位(-1 唤醒锁,大于0)回去尝试唤醒锁或者(TODO,看不懂了,感觉有两个队列)

? ? ? ? 1.2 设置中断标志位(selfInterrupt()):前面的操作会取消中断标志位,这一步是为了复位中断标志位

2.lock.unlock(解锁):解锁逻辑很简单,分为两步

???2.1 尝试将重入标志state值减1判断是否等于0,tryRelease(arg),如果为0,复原独占锁为null

? ? ? ? 2.2? 上一步的state为0时并且链表不为空,唤醒标志位waitstatus不为0,阻塞线程

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReentrantLockDemo {

    private static  int sum = 0;
    private static Lock lock = new ReentrantLock();
    //private static TulingLock lock = new TulingLock();

    public static void main(String[] args) throws InterruptedException {

        for (int i = 0; i < 3; i++) {
            Thread thread = new Thread(()->{
                //加锁
                lock.lock();
                try {
                    // 临界区代码
                    // TODO 业务逻辑:读写操作不能保证线程安全
                    for (int j = 0; j < 10000; j++) {
                        sum++;
                    }
                } finally {
                    // 解锁
                    lock.unlock();
                }
            });
            thread.start();
        }

        Thread.sleep(2000);
        System.out.println(sum);
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-05-07 11:02:36  更:2022-05-07 11:03:25 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:53:13-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码