目录
synchronized
是 Java 中的一个关键字,翻译成中文是同步的意思,主要解决的是多个线程之间访问资源的同步性,可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。
在 Java 早期版本中,synchronized
属于 重量级锁,效率低下。这是因为监视器锁(monitor)是依赖于底层的操作系统的 Mutex Lock
来实现的,Java 的线程是映射到操作系统的原生线程之上的。如果要挂起或者唤醒一个线程,都需要操作系统帮忙完成,而操作系统实现线程之间的切换时需要从用户态转换到内核态,这个状态之间的转换需要相对比较长的时间,时间成本相对较高。
不过,在 Java 6 之后, synchronized
引入了大量的优化如自旋锁、适应性自旋锁、锁消除、锁粗化、偏向锁、轻量级锁等技术来减少锁操作的开销,这些优化让 synchronized
锁的效率提升了很多。因此, synchronized
还是可以在实际项目中使用的,像 JDK 源码、很多开源框架都大量使用了 synchronized
。
关于偏向锁多补充一点:由于偏向锁增加了 JVM 的复杂性,同时也并没有为所有应用都带来性能提升。因此,在 JDK15 中,偏向锁被默认关闭(仍然可以使用 -XX:+UseBiasedLocking
启用偏向锁),在 JDK18 中,偏向锁已经被彻底废弃(无法通过命令行打开)。
以 32 位虚拟机为例:
Monitor 被翻译为 监视器 或 管程 。如果使用重量级锁给对象上锁,那么对象会通过对象头的 Mark Word 关联一个 Monitor。
synchronized
关键字修饰一个代码块或方法时,程序实际上就是在请求获取该对象上的 monitor 锁,以便对代码块或方法单独执行的控制wait()
状态的线程队列,即调用 wait()
方法的线程。wait()
方法,将释放当前持有的 Monitor,_owner 变量恢复为 null,_count 自减 1,同时该线程进入 _WaitSet 集合中等待被唤醒。