锁的四种状态:无锁状态,偏向锁状态,轻量级锁状态,重量级锁状
偏向锁
在并发量较小的情况下,对象的锁会从无锁转换成偏向锁,当获取到对象锁的线程,会在对象的头部存放该线程的ID。偏行锁的标志位为1,此时锁的标志位也是为1。抢锁是通过CAS操作完成的,抢锁的线程若在对象的头部信息更新为了该线程的地址,则表示是抢锁成功。
轻量级锁
多个线程争夺对象的锁时,JVM会把对象的锁转换成无锁状态,并且每个线程会在自己的栈帧中开辟一个空间叫做Lock Reword。然后把对象的MarkWord复制到每个线程的LockReword中,被称为DisplacedMarkWord,当前某个对象尝试去该对象的锁时,会通过CAS操作进行把当前线程的LockWord的地址更新到对象的MarkWord中去,并把锁的标志位改为00,则表示抢锁成功,获得了该对象的锁。为获取锁的线程则会进入自旋状态
重量级锁
由于在轻量级锁中为获取锁的线程在自旋过程中循环多次,造成大量的CPU占用浪费,所以升级为重量级锁
锁升级的过程:
当一个线程访问一个同步代码块时,会去查看Mark Word里面存放的线程ID是不是当前的线程ID,如果是则此时锁是偏向锁,可直接运行代码;如果不是,则通过CAS操作来进行改变Mark Word里面的线程ID为自己的线程ID,修改成功则之前的线程不存在了,锁为当前线程所有;修改失败,则通知之前的线程停止,并升级锁为轻量级锁,在通过轻量级锁进行竞争锁。进入轻量级锁后,每个线程都会把锁Mark Word中记录复制到自己的Dispalced Mark Word中去,然后通过CAS操纵把锁的Mark Word指向锁记录的指针,如果操作成功,则获得该锁。失败则表示,该锁已经被其他线程的锁记录替换了。当前线程就会通过自旋的方式来进行获取锁,也就是等待其他线程执行完后释放锁后进行获取锁,若自旋失败则会重量级锁升级为重量级锁后,自旋的线程会进行阻塞,等待会唤醒。
补充:
创建一个对象,该对象包括结构组成:
对象组成部分:对象头部信息、对象实例、对齐区域
对象头:MarkWord:存放锁的信息、hashCode、GC的年龄;mateDate Adress:存放对象类型的指针;arrayLength:数组长度(当前对象是数组才有其对象)