编程语言
首页 > 编程语言> > Java并发之锁详解

Java并发之锁详解

作者:互联网

Java并发之锁

一、临界区

二、线程安全

三、解决临界区线程安全问题

四、Java对象头

五、重量级锁 Monitor

5.1 synchronized

5.1.1 synchronized加锁流程

前提条件:synchronized必须是进入同一个对象的monitor;不加synchronized的对象不会关联monitor

六、轻量级锁

6.1 轻量级锁加锁流程

  1. 创建锁记录(Lock Record)对象,每个线程的栈都会包含一个锁记录的结构(不可见,不是Java层面),内部包含两部分,一部分是对象的地址(指针)Object reference,另一部分是加锁对象的Mark Word
  2. 让锁记录中的Object reference指向锁对象,并尝试用cas替换对象的Mark Word,将Mark Word的值存入锁记录,将对象的Mark Word存入锁记录地址以及加锁状态位(替换的目的就是为了加锁),加锁状态位为01表示无锁状态,00表示轻量级锁状态,10表示重量级锁状态,11表示Marked for GC
  3. 若cas替换成功,对象头中存储了锁记录地址和状态00,表示由该线程给对象加轻量级锁(cas保证替换操作是原子性的,不会被打断)

6.2 CAS失败的情况

  1. 如果是其他线程已经持有了该Object的轻量级锁,这时表明有竞争,进入锁膨胀过程
  2. 如果是自己执行了锁重入,那么再添加一条Lock Record作为重入的计数,即锁记录数对应加锁的次数,锁重入的锁记录中的加锁对象的Mark Word为null

6.3 轻量级锁解锁流程

  1. 当退出synchronized代码块(解锁时),如果有取值为null的锁记录,表示有重入,这时重置锁记录,表示重入计数减一
  2. 当退出synchronized代码块(解锁时)锁记录的值不为null,这时使用cas将Mark Word的值恢复给对象
    成功,则解锁成功
    失败,说明轻量级锁进行了锁膨胀或已经升级为重量级锁,进入重量级锁解锁流程

七、偏向锁(轻量级锁优化)

八、锁膨胀

九、自旋优化(重量级锁优化)

十、锁消除

10.1 逃逸分析

十一、锁粗化

十二、锁粒度

12.1 死锁

12.1.1 死锁的条件

  1. 互斥使用,当资源被一个线程使用(占有)时,别的线程不能使用
  2. 不可抢占,资源请求者不能强制从资源占有者手中夺取资源,资源只能由资源占有者主动释放
  3. 请求和保持,当资源请求者在请求其他的资源的同时保持对原有资源的占有
  4. 循环等待,存在一个等待队列:P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路

12.1.2 定位死锁

12.2 活锁

12.3 饥饿

  1. 如果优先级高的线程一直抢占优先级低线程的资源,导致低优先级线程无法得到执行,则产生饥饿
  2. 一个线程一直占着一个资源不放而导致其他线程得不到执行

标签:之锁,加锁,Java,对象,详解,线程,Word,重量级,轻量级
来源: https://blog.csdn.net/LvJzzZ/article/details/115733847