synchronized的加锁过程是怎么样的?
2 个回答
想多了全是问题,想开了全是答案。Rose的肉丝儿### synchronized的加锁过程 在Hotspot JVM中,每个Class都有一个对象,每个对象由以下三部分组成: 1. 对象头 2. 实例数据 3. 对齐填充(确保Java对象大小是8字节的倍数) 每个对象的对象头包含了锁信息,synchronized的锁存储在对象头中。 #### 对象头 对象头有两种类型: - 数组类型:对象头占用3字节 - 非数组类型:对象头占用2字节 对象头通常由两部分组成: 1. **Mark Word**:存储对象的运行时数据,如HashCode、分代年龄和锁标志位信息。Mark Word是一个非固定的数据结构,随着锁标志位的变化而变化。 2. **Klass Pointer**:指向类元数据的指针。 #### Monitor Monitor是实现synchronized的关键机制,每个Java对象都有一个关联的Monitor。Monitor是一种同步工具或机制,通过Monitor实现方法和代码块的同步。 在synchronized修饰的方法和代码块中,加锁过程有一些区别: 1. **synchronized代码块**:使用`monitorenter`和`monitorexit`指令实现同步。当线程执行到`monitorenter`时,需要先获取Monitor锁,才能继续执行;当执行到`monitorexit`时,释放锁。 2. **synchronized方法**:通过在方法访问标识符(flags)中加入`ACCSYNCHRONIZED`标志来实现同步功能。当线程执行带有`ACCSYNCHRONIZED`标志的方法时,需要获取Monitor锁。 #### Monitor锁 Monitor锁与对象关联,当Monitor被持有后,处于锁定状态。synchronized在JVM中通过进入和退出Monitor对象,通过成对的`MonitorEnter`和`MonitorExit`指令实现同步。 Monitor锁的工作原理包括以下几个步骤: 1. **线程竞争锁**:所有新的线程进入EntryList中竞争锁。 2. **锁的获取**:线程通过CAS把monitor的owner字段设置为自己,获取到锁,其他线程进入阻塞状态。如果线程是第一次进入该monitor,将recursions设置为1;如果是重入锁,recursions递增。 3. **锁的释放和等待**:获取锁的线程执行`wait`方法时,释放锁,进入waitset中,通知waitset中其他线程重新竞争锁。 4. **重新竞争锁**:锁被释放后,waitset和EntryList中的其他线程重新竞争锁。 5. **锁的释放**:线程执行完同步代码,释放锁,通知其他线程竞争锁。执行monitorexit时,monitor的进入数减少1,最终释放锁。 通过上述步骤,实现了synchronized的加锁和释放过程,确保了线程安全。编辑于 2024-05-09 00:21 •IP属地 北京举报评论收藏1
你爱你的玫瑰是因为你在你的玫瑰上花了太多的时间!吴敏### synchronized的加锁过程 在Java中,`synchronized`关键字用来实现同步机制,确保在多线程环境下对共享资源的安全访问。它涉及几种锁的实现,包括无锁、偏向锁、轻量级锁和重量级锁,锁的升级过程如下: 1. 无锁状态 2. 偏向锁 3. 轻量级锁 4. 重量级锁 锁的升级过程是不可逆的,即锁只能从低级别升级到高级别,而不能降级。偏向锁可以被重置为无锁状态。 #### 锁的标志位信息 在对象头的 Mark Word 中存储着锁的标志位信息,不同锁状态对应的标志位如下图所示:  #### 锁升级过程 1. **无锁状态**:在无锁状态下,对象头中锁标志位为01,是否为偏向锁标志位为0。 2. **无锁升级为偏向锁**: - 检查对象头的 Mark Word 中的线程ID与当前线程ID是否一致。 - 一致则直接执行同步代码或方法。 - 不一致则通过CAS设置当前线程ID到 Mark Word 中,并将偏向锁标志位设为1。 - 在 Mark Word 和栈帧中记录偏向锁的线程ID。 - 执行同步代码或方法。 .jpg") 3. **偏向锁升级为轻量级锁**: - 如果偏向锁持有的线程ID与当前线程ID不一致,则尝试通过CAS设置当前线程ID。 - CAS设置失败,证明存在多线程竞争情况,触发撤销偏向锁。 - 到达全局安全点,偏向锁的线程被挂起,偏向锁升级为轻量级锁。 .jpg") 4. **轻量级锁状态**: - 无锁状态下,关闭偏向锁功能,直接升级为轻量级锁。 - 锁标志位设置为00,执行同步代码或方法。 - 在多线程竞争情况下,自旋尝试获取锁,直到自旋次数达到阈值。 - 自旋失败,则轻量级锁升级为重量级锁。 5. **轻量级锁升级为重量级锁**: - 自旋一定次数后仍未获取到锁,轻量级锁升级为重量级锁。 - 重量级锁依赖操作系统的互斥锁(Mutex Lock)来实现。 - 锁标志位设置为10,等待锁的线程进入阻塞状态,防止CPU空转。 .jpg") #### 注意事项 - **锁可以升级但不能降级**:一旦锁升级到更高级别,就不能回退到低级别,但偏向锁状态可以被重置为无锁状态。 - **自旋锁的次数**:轻量级锁在自旋一定次数后未获取到锁,会升级为重量级锁。自旋次数的默认值为10次,可以通过虚拟机参数调整。 通过上述过程,可以了解 `synchronized` 关键字在Java中加锁的具体机制及其不同状态下的工作原理。编辑于 2024-03-13 23:42 •IP属地 北京举报评论收藏
公众号进入网站体验更佳

