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的过程
- head 队列头部,一般为空
- node 抢占锁的线程,有序
- prev 链接(在原始CLH锁中不使用)主要用于处理取消。 如果取消某个节点,则其后继节点(通常)会重新链接到未取消的前任节点
持续更新中 ….,个人理解,且行且珍惜
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END