AQS基础版源码分析,锁的基础内容过去简单, 本文不做阐述

AQS(AbstractQueuedSynchronizer) 抽象排队同步器

为什么会存在AQS , synchronized真的不香了?

简单来说,java 中线程的实现 是通过 java->jvm->os函数—>(cpu,内存)进行调度,并且sync加锁的本质是通过操作系统 pthread_lock 指令来的。

可以看出sync是基础操作系统级别的调用,通过用户态,内核态的转变,造成了很多大性能浪费,所以Java 自推出了AQS之后,锁的性能达到了一个新层次;

AQS 以内存中的用户层实现有效的打击的synchronized的地位,但是之后,例如到了现在的所有人都知道的jdk8,snyc也不甘示弱,性能也优化到不弱于AQS的地位。毕竟sync才是java的亲儿子.

从自旋锁到AQS的进化,假如你是设计者 ?

  • while(!true) ,一直抢占锁,优点代码简单,缺点不停的自转,CPU承受不住

  • while(!true) {
    //todo yield() 方法,让出cpu,
    缺点:线程过多的时候,就算让出了CPU资源,但是还是会有很多的线程在竞争,而且让出的次数太多,也有性能问题
    }

  • 使用Thread.sleep(time)来准确的在该让出CPU的时候,让出CPU,但是睡眠的时间无法掌控,可能让获取锁的时间过长,造成业务操作时间延长,得不偿失,无法解决根本的问题

  • 最后 queue+自旋,样例代码 ,非常简单的个人理解

LockSupport 为了更好的操作线程的睡眠和唤醒 AQS的特点之一 方法:
  1.park 当前线程睡秒/堵塞
  2.unpark(thread) 唤醒指定的线程
{
        Queue parkQueue; // 线程队列,从队列头部到队列尾部依次获得到锁
        
        parkQueue.add(currentThread);//假如进来线程进行抢占锁;
        parkQueue.add(currentThread);//假如进来线程进行抢占锁'
        
        进入队列时,LockSupport.park(currentThread);
        
        while(true) {
            LockSupport.unpark(currentThread); // 依次从队列的头部的线程获取锁
        }
}
复制代码

AQS的过程

image.png

  • head 队列头部,一般为空
  • node 抢占锁的线程,有序
  • prev 链接(在原始CLH锁中不使用)主要用于处理取消。 如果取消某个节点,则其后继节点(通常)会重新链接到未取消的前任节点

持续更新中 ….,个人理解,且行且珍惜

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享