synchronize存在着无锁、偏向锁、轻量级锁和重量级锁四种状态,会随着竞争的激烈逐渐升级。
偏向锁:
顾名思义,就是偏向第一个获得该对象的锁的线程,当线程请求到锁对象后,将锁对象的偏向标志改为1。然后使用CAS操作将线程的ID记录在锁对象的Mark Word中。以后该线程可以直接进入同步块,进去以后标志计数加一。但是,一旦有第二条线程需要竞争锁,那么偏向模式立即结束,进入轻量级锁的状态。
轻量级锁:
升级为轻量级锁以后,线程进入同步块的时候,就会在线程的栈帧创建一个Lock Record,并把锁对象的mark word拷贝进去,然后JVM使用CAS操作尝试将Mark Word更新为指向Lock Record的指针(对象标志位为00),如果更新成功代表获取锁成功就执行同步操作。更新失败就一直自旋,超过10次以后就变成重量级锁,所有未获得锁的线程都阻塞队列等待。
轻量级锁解锁时,会使用CAS将之前复制在栈桢中的 Displaced Mard Word 替换回 Mark Word 中。如果替换成功,则说明整个过程都成功执行,期间没有其他线程访问同步代码块。
重量级锁:
重量级锁是互斥锁,存在着一个从用户态到核心态的切换,很浪费时间。
同步代码块:
是通过monitorenter和monitorexit来实现的,它会在同步代码块的前后加上这两个指令,线程执行monitorenter指令代表该锁(就是和对象关联的monitor)被该对象持有,执行完同步代码块以后就会唤醒阻塞的线程。
同步方法:
它实现在方法调用和返回操作之中。JVM可以从方法常量池中的方法表结构(method_info Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时,将会 检查方法的 ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有monitor,然后再执行方法,最后在方法完成时释放monitor。