synchronized 的底层是使用操作系统的 mutex lock 实现的。synchronized 用的锁是存在 Java 对象头里的。JVM 基于进入和退出 Monitor 对象来实现方法同步和代码块同步。代码块同步是使用 monitorenter 和 monitorexit 指令实现的,monitorenter 指令是在编译后插入到同步代码块的开始位置,而 monitorexit 是插入到方法结束处和异常处。任何对象都有一个 monitor 与之关联,当且一个 monitor 被持有后,它将处于锁定状态。

Mutex Lock

监视器锁(Monitor)本质是依赖于底层的操作系统的 Mutex Lock(互斥锁)来实现的。每个对象都对应于一个可称为互斥锁的标记,这个标记用来保证在任一时刻,只能有一个线程访问该对象。
互斥锁用于保护临界区,确保同一时间只有一个线程访问数据。对共享资源的访问,先对互斥量进行加锁,如果互斥量已经上锁,调用线程会阻塞,直到互斥量被解锁。在完成了对共享资源的访问后,要对互斥量进行解锁。

底层原理

我们知道,synchronized 修饰实例方法,相当于 synchronized(this)。修饰静态方法,相当于 synchronized(this.class)。修饰代码块的形式是 synchronized(Object)。可见 synchronized 相关的代码最后都可以归结为 synchronized(Object) 的形式。

ReentrantLock 相比

synchronized 与 ReentrantLock 相比,synchronized 与 ReentrantLock 的性能基本持平。ReentrantLock 只是提供了 synchronized 更丰富的功能,而不一定有更优的性能,所以在 synchronized 能实现需求的情况下,优先考虑使用 synchronized 来进行同步。

synchronized 方法

每个 synchronized 方法都必须获得调用该方法的类实例的锁方能执行,否则所属线程阻塞,方法一旦执行,就独占该锁,直到从该方法返回时才将锁释放,此后被阻塞的线程方能获得该锁,重新进入可执行状态。

synchronized 代码块

synchronized 关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。

synchronized 静态方法

作用在静态的方法,取得的锁很特别,是当前调用这个方法的对象所属的类对象。

相关文章: