简单过程:
①给java代码块或方法加一个Synchronized修饰
②在编译时会自动在这段Synchronized修饰的代码上下添加 “monitorenter”(监视器开始) 与 “monitorexit”(监视器结束) 标识
③在JVM执行过程中进行加锁处理,会自动进行锁的升级(无锁-偏向锁-轻量级锁(自旋锁)-重量级锁)
④其最底层的汇编指令使用的即为:lock cmpxchg
锁升级过程:
对象刚创建时为无锁状态,
当第一个线程来访问时,上偏向锁,就是给该对象贴一个标签标识偏向该第一个访问的线程,
当多个线程争抢时,锁自动升级为轻量级锁,也称为自旋锁/自适应自旋锁,实现方式即为CAS比较与交换,抢占到锁资源则执行,抢占不到则自旋等待
当自旋达到一定次数或者自旋线程达到一定数量,jvm会自动将锁升级为重量级锁,此为操作系统级别的锁,由操作系统执行的用户态转为内核态进行处理,将自旋的线程放置在等待队列中等待依次执行。
上锁是对对象进行上锁,锁的信息存放在对象头(mark work与class pointer 为对象头)中,对象在堆中的内存布局如下:
mark word 8个字节 存放锁信息、分代年龄、GC信息
class pointer 对象指针,在开启指针压缩的情况下占4个字节,未开启指针压缩占8个字节,指向该对象属于哪个类
实例数据 存放对象属性等信息,无数据即为0个字节
对齐位 如果对象整体字节数不为8的倍数,则需补齐,提高效率
new Object() 占多少个字节? 答:16个字节。 mark word:8 , class pointer:4 / 8 , 实例数据:0 ,对齐:4 / 0
其他概念:
锁消除:如果加锁的方法在普通方法中使用,不存在线程安全问题,则JVM会自动消除该锁资源
锁粗化:如果在循环中调用加锁的方法,JVM会自动将锁粗化到循环外部,避免每次循环加锁解锁,提高执行效率。
Synchronized为可重入锁,A方法加锁,调用加锁的B方法,锁可重入,不会导致死锁 。
Synchronized代码块或方法中需处理异常,防止内部抛异常后释放锁资源,其他线程拿到锁资源后处理错误的数据。