synchronized通过对象内部的一个叫做监视器锁的东西来实现的。
监视器锁本身依赖于操作系统底层的互斥锁Mutex Lock来实现的,同步代码块是通过monitorenter
和moniterexit
指令来获取线程的执行权。同步方法是通过加ACC_SYNCHONIZED
标识获取线程的执行权。
操作系统实现线程之间的切换需要从用户态转换到核心态,成本很高,状态转换要花费比较长的时间。
这就是synchronized效率低的原因。这种依赖于操作系统MutexLock实现的锁成为重量级锁。
synchronized v.s. volatile
Volatile:内存可见(不保证原子性,不保证互斥性);防止CPU指令重排(内存屏障)
扩展:
如何保证内存可见?
JMM通过控制主内存与每个线程的本地内存之间的交互,来为Java程序员提供内存可见性保证。
什么是内存屏障?
MM属于语言级的内存模型,它确保在不同的编译器和不同的处理器平台之上,通过禁止特定类型的编译器重排序和处理器重排序,为程序员提供一致的内存可见性保证。
happens-before规则
happens-before表示的是前一个操作的结果对于后续操作是可见的,它是一种表达多个线程之间对于内存的可见性。所以我们可以认为在 JMM 中,如果一个操作执行的结果需要对另一个操作可见,那么这两个操作必须要存在happens-before关系。这两个操作可以是同一个线程,也可以是不同的线程。