不知道AQS 的阻塞队列是否是属于Java层面的实现,而重量级锁则是操作系统实现?
AQS和Synchronized 的重量级锁的区别?
谢谢!困惑少多了,这里的汇编码现在是comxchg 是说明目前是采用的是轻量级锁对吧?
xiao 应该是吧 , 所以有亲爸爸优化后的 synchronized , 性能也还好
请问AQS是如何实现阻塞的,难道不需要借助操作系统实现线程的阻塞和唤醒吗?如果需要那感觉倒和synchronized早期版本一样了
谢谢!刚看了论文,这里用的是park来阻塞线程,如果park底层也是操作系统层级的,那这里感觉aqs和synchronized的主要区别就在于:aqs是自己在java层面实现的阻塞队列,而synchronized是借助操作系统实现的阻塞队列,不知道可否这样理解
也可以,synchronize是JVM级别的锁原语,如果是重量级锁状态的话是基于操作系统的锁实现的,锁的等待队列由操作系统管理。AQS应该把等待队列拉出来自己做,只是借用了操作系统的API阻塞和解除阻塞线程来暂停执行,等待锁可用而已。
我又来了,感觉还是不太理解,lock和早期的synchronized都需要对线程进行唤醒和阻塞,那为什么lock比synchronized快呢?好像都需要经历内核态和用户态的切换呀?
https://concurrency-interest.altair.cs.oswego.narkive.com/Bx94AChl/why-is-reentrantlock-faster-than-synchronized 谷歌了一下,这里有一个链接,doug lea曾经亲自回答了这个问题,事实上aqs更快的原因还是在于,aqs在实现的时候相比于synchronized做了很多的优化,而且本身设计Lock的初衷也是在于提供更高的灵活性,在此基础上对性能做了优化
- 已编辑
最近在看 HotSpot,有了更深刻的理解
AQS 和 synchronized 都是用的 park (这里只讨论 posix 实现)
- AQS 使用的
LockSupport.park()
最终调用的是JavaThread->parker()->park()
,其中 parker() 返回 Parker 类型指针,JavaThread 继承 Thread,Parker 继承os::PlatformEvent
- synchronized 调用的是
Thread->_ParkEvent->park()
,其中 _ParkEvent 是 ParkEvent 类型指针,ParkEvent 也是继承os::PlatfomEvent
os::PlatformEvent
有 park() 方法,且 Parker 对 park 方法重写了- park 方法都是用 pthread 的条件变量来实现
在上面的前提下,去看它俩的区别
- AQS 的 unpark 时机由上层把控,synchronized 则由 VM 把控。所以我现在觉得它们效率上差距其实很有限,就看哪个优化得好。比如 synchronized 的等待队列(叫CXQ)中的第一个等待的线程会以 1ms, 8ms, 64ms... 这样简单的退避算法来 park,这里假设 AQS 用的是频率更高的退避算法,自然会发现 synchronized 貌似更慢些,当然这只是假设,AQS 具体怎么优化我没去比较
- 正是由于 AQS 的 unpark 由上层控制,所以条件变量的 Spurious wakeup 问题也得自己解决,
LockSupport.park()
的 Java doc 也说了 The call spuriously (that is, for no reason) returns. ;而 synchronized 的 Spurious wakeup 则由 VM 控制住了,不会对程序产生影响。- 这个区别产生的原因,就是上面提到的 Parker 对 park 方法重写了。原本
os::PlatformEvent::park()
中pthread_cond_wait()
外面用的是 while 包着的,而 Parker 重写后的 park 方法则改成了用 if 包着,就这样把 Spurious wakeup 问题抛给了上层
- 这个区别产生的原因,就是上面提到的 Parker 对 park 方法重写了。原本