Java 对象监视器的先发生顺序语义在§17.4.5中描述为:
wait
类(第 17.2.1 节)的方法Object
具有与之关联的锁定和解锁操作;它们的happens-before关系由这些关联的动作定义。
未指定这是否仅适用于 Java 管理的对象或任何数据。毕竟,Java 并不关心 Java“世界”之外发生的事情。但这也意味着我们可以将规范外推到Java 世界中可访问的任何数据。然后与堆的关系变得不那么重要了。毕竟,如果我同步线程,为什么它不能直接用于 ByteBuffer 呢?
为了确认这一点,我们可以看看它是如何在 OpenJDK 中实际实现的。
如果我们仔细观察,我们会发现,ObjectMonitor::wait
除其他外:
OrderAccess::fence();
并且( /ObjectMonitor::exit
的业务端)确实:notify
notifyAll
OrderAccess::release_store_ptr (&_owner, NULL) ;
OrderAccess::storeload() ;
两者都fence()
导致storeload()
全局 StoreLoad 内存栅栏:
inline void OrderAccess::storeload() { fence(); }
在 SPARC 上,它生成membar
指令:
__asm__ volatile ("membar #StoreLoad" : : :);
在 x86 上,它转到 membar(Assembler::StoreLoad)
并随后:
// Serializes memory and blows flags
void membar(Membar_mask_bits order_constraint) {
if (os::is_MP()) {
// We only have to handle StoreLoad
if (order_constraint & StoreLoad) {
// All usable chips support "locked" instructions which suffice
// as barriers, and are much faster than the alternative of
// using cpuid instruction. We use here a locked add [esp],0.
// This is conveniently otherwise a no-op except for blowing
// flags.
// Any change to this code may need to revisit other places in
// the code where this idiom is used, in particular the
// orderAccess code.
lock();
addl(Address(rsp, 0), 0);// Assert the lock# signal here
}
}
}
所以你有了它,它只是 CPU 级别的内存屏障。引用计数和垃圾收集在更高的层次上发挥作用。
这意味着至少在 OpenJDK 中,之前发出的任何内存写入都将在之后发出的任何读取之前Object.notify
排序。Object.wait