在多线程访问共享资源的时候,经常会带来可见性和原子性的安全问题。为了解决这类线程安全的问题,Java提供了同步机制、互斥锁机制,这些机制保证了在同一时刻只有一个线程能访问共享资源。这些机制的保障来源于监视锁Monitor,每个对象都拥有自己的监视锁Monitor。
Monitor是一种同步工具,也说是一种同步机制,它通常被描述为一个对象,主要特点是:对象(Monitor)的所有方法都被“互斥”的执行。好比一个Monitor只有一个运行“许可”,任一个线程进入任何一个方法都需要获得这个“许可”,离开时把许可归还。
在JVM源码中,Monitor的实现中有几个关键的属性:
_owner:指向持有ObjectMonitor对象的线程
_WaitSet:存放处于wait状态的线程队列
_EntryList:存放处于等待锁block状态的线程队列
_recursions:锁的重入次数
_count:用来记录该线程获取锁的次数
说明:当多个线程同时访问一段同步代码时,首先会进入_EntryList队列中,当某个线程获取到对象的monitor后进入_Owner区域并把monitor中的_owner变量设置为当前线程,同时monitor中的计数器_count加1。即获得对象锁。
若持有monitor的线程调用wait()方法,将释放当前持有的monitor,_owner变量恢复为null,_count自减1,同时该线程进入_WaitSet集合中等待被唤醒。
若当前线程执行完毕将释放monitor(锁)并复位变量的值,以便其他线程进入获取monitor(锁)。
在JDK1.6之前:sychronized的加锁和解锁实现会直接调用monitor的加锁和解锁方法,这种被称为重量级锁。因为Java线程是映射到操作系统原生线程上的,如果要阻塞或唤醒一个线程需要到操作系统层面(从用户态转换到核心态),状态之间的转换要花费很多的时间。
在JDK1.6之后对锁做了优化,出现了轻量级锁,偏向锁,锁消除,适应性自旋锁,锁粗化。为了在线程之间更高效的共享数据 ,解决竞争问题