AQS详解 1

1.本文不讲概念,用jdk8调试一步一步搞清AQS这个东西,请耐心并跟着本文实操

现在我们先实现下面这个类:

public class MutexLock {
	static class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 3601133938511592218L;
        /***
         *  尝试获取锁
         */
        protected boolean tryAcquire(int arg) {
            // 当 state 值为0时,然后就改为1,否则就返回false也不修改state值
            if (compareAndSetState(0, 1)) {
                // 设置当前线程为 独占线程
                setExclusiveOwnerThread(Thread.currentThread());
                return true;
            }
            return false;
        }
		//尝试释放锁
        @Override
        protected boolean tryRelease(int arg) {
            if (getState() == 0) {
                // state 为 0 说明当前同步块中没有锁了,无需释放
                throw new IllegalMonitorStateException();
            }
            //当前独占线程 设置为null
            setExclusiveOwnerThread(null);
            // 将状态变量的值设为 0,以便其他线程可以成功修改状态变量从而获得锁
            setState(0);
            return true;
        }

        // 当前线程是否被独占
        @Override
        protected boolean isHeldExclusively() {
            return getState() == 1;
        }
    }
    // 将操作代理到 Sync 上
    private final Sync sync = new Sync();

    public void lock() {
        sync.acquire(1);
    }
    /**
     * 试图释放此锁
     */
    public void unlock() {
        sync.release(1);
    }

上面代码仿照了ReentrantLock,实现了lock和unlock方法,实际操作都是Sync这个内部类操作的。
下面我们来测试下:

 public static void main(String[] args) throws InterruptedException {
        // final ReentrantLock lock = new ReentrantLock();
        final MutexLock lock = new MutexLock();
        ///  代码A
        lock.lock(); 
        new Thread() {
            public void run() {
                //代码B
                lock.lock();
                System.err.println("==============");
                lock.unlock();
            };
        }.start();
        Scanner sc = new Scanner(System.in);
        System.out.print("Please enter a string : ");
        String lein = sc.next();
        if (lein.equals("1")) {
            //代码C
            lock.unlock();
        }
    }

上面代码大致解释:

  1. 主线程加锁,然后子线程lock时拿不到锁会阻塞等待
  2. 主线程在控制台输入1 回车时,主线程unlock,子线程被唤醒直到执行完毕!

调试分析

1.代码A 块的执行

我们调用代码A 【lock.lock();】 方法,跟踪进到AQS类的acquire方法
在这里插入图片描述
执行子类的tryAcquire方法, 调试我们返回true。
在这里插入图片描述

返回上层函数,直接返回,到此main函数的代码A 【lock.lock();】 方法已经执行完毕!在这里插入图片描述
执行完总结:
AQS的两个成员变量
在这里插入图片描述
在这里插入图片描述
state 的值 变成1。
exclusiveOwnerThread的值变成 当前main函数线程的引用。

2.代码B块的执行

同样跟踪到下面tryAcquire方法,整个方法返回false
在这里插入图片描述
回到上层方法,进入addWaiter
在这里插入图片描述
addWaiter方法如下
在这里插入图片描述
执行enq方法之前我们观察Node的数据结构和值如下(记住)
在这里插入图片描述
进入enq方法,进入第一次循环。
在这里插入图片描述

第二次序号循环在这里插入图片描述
到此我们能想象出如下数据结构图
在这里插入图片描述
到此我们有了Node1节点Node2节点

继续走代码
在这里插入图片描述
返回上一层,执行acquireQueued函数在这里插入图片描述
acquireQueued函数的第一次循环在这里插入图片描述

下面我们看shouldParkAfterFailedAcquire这个方法
在这里插入图片描述

上面执行完后,需要知道Node1节点的waitStatus变量变成-1在这里插入图片描述

第二次循环,上面shouldParkAfterFailedAcquire返回false,所以直接进入第二次循环
在这里插入图片描述
第二次进入shouldParkAfterFailedAcquire方法
在这里插入图片描述
返回上一层在这里插入图片描述
进入parkAndCheckInterrupt方法
在这里插入图片描述
在这里插入图片描述

代码B块的执行总结
1.阻塞了当前子线程,利用LockSupport.park工具阻塞
2.在AQS内部构造了如下链表数据结构
在这里插入图片描述
今天就讲到这里吧,分析不清楚的敬请谅解。可以加我qq一起讨论。
老生常谈:深圳有爱好音乐的会打鼓(吉他,键盘,贝斯等)的程序员和其它职业可以一起交流加入我们乐队一起嗨。我的QQ:657455400 表演视频实例https://v.qq.com/x/page/f0517awx0x4.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值