学游者

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Synchronized关键字

一、原理

1.1 对象头

  • 对象:对象头、实例变量、填充数据
  • 对象头结构(2个字,数组多出来的1个字记录的是数组长度)
虚拟机位数 对象头结构 说明
32/64 bit Mark Word 存放对象运行时数据:哈希码(hashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等等
32/64 bit Class Metadata Address 类型指针指向对象的类元数据(instanceof)、JVM通过这个指针获取对象是那个类的实例

1.2. Mark Word 结构

  • 32位正常
锁状态 25bit 4bit 1bit(是否是偏向锁) 2bit(锁标志位)
无锁状态 对象HashCode 对象分代年龄 0 01
  • 32位细分

二、锁队列

  • C++的 ObjectMonitor
ObjectMonitor() {
    _header       = NULL;
    _count        = 0; //记录个数
    _waiters      = 0,
    _recursions   = 0;
    _object       = NULL;
    _owner        = NULL;  "当前线程指针"
    _WaitSet      = NULL; "处于wait状态的线程,会被加入到_WaitSet队列"
    _WaitSetLock  = 0 ;
    _Responsible  = NULL ;
    _succ         = NULL ;
    _cxq          = NULL ;
    FreeNext      = NULL ;
    _EntryList    = NULL ; "处于等待锁block状态的线程,会被加入到该列表队列"
    _SpinFreq     = 0 ;
    _SpinClock    = 0 ;
    OwnerIsThread = 0 ;
  }
  • 示意图
    • 先进入 _EntryList集合排队
    • 然后获取锁,_Owner标记位当前线程。
    • 当执行 wait() 方法,则进入 _WaitSet集合中,等待唤醒

三、各阶段锁

  • 偏向锁(没有锁竞争)<JDK1.6>

    • 经过研究发现,在大多数情况下,锁不仅不存在多线程竞争,而且总是由同一线程多次获得,因此为了减少同一线程获取锁(会涉及到一些CAS操作,耗时)的代价而引入偏向锁。
    • 偏向锁的核心思想是
      • 如果一个线程获得了锁,那么锁就进入偏向模式,此时Mark Word 的结构也变为偏向锁结构
      • 当这个线程再次请求锁时,无需再做任何同步操作,即获取锁的过程,这样就省去了大量有关锁申请的操作,从而也就提供程序的性能
        • 对于没有锁竞争的场合,偏向锁有很好的优化效果,毕竟极有可能连续多次是同一个线程申请相同的锁。
        • 但是对于锁竞争比较激烈的场合,偏向锁就失效了,因为这样场合极有可能每次申请锁的线程都是不相同的,因此这种场合下不应该使用偏向锁,否则会得不偿失,需要注意的是,偏向锁失败后,并不会立即膨胀为重量级锁,而是先升级为轻量级锁
  • 轻量级锁(同步周期内都不存在竞争:交替执行)<JDK1.6>

    • 倘若偏向锁失败,虚拟机并不会立即升级为重量级锁,它还会尝试使用一种称为轻量级锁的优化手段(1.6之后加入的),此时Mark Word 的结构也变为轻量级锁的结构。
    • 轻量级锁能够提升程序性能的依据是对绝大部分的锁,在整个同步周期内都不存在竞争,注意这是经验数据。
    • 轻量级锁所适应的场景是 线程交替执行同步块的场合如果存在同一时间访问同一锁的场合,就会导致轻量级锁膨胀为重量级锁
  • 重量级锁(同一时间访问同一锁)

    • 线程挂起

四、案例

  • java 代码
package com.fxl.fight2.service.syn;

public class SyncObject {

	public int i;

	public void syncTask() {
		// 同步代码库
		synchronized (this) {
			i++;
		}
	}
}
  • javap 反解析
public class com.fxl.fight2.service.syn.SyncObject {
  public int i;

  public com.fxl.fight2.service.syn.SyncObject();
    Code:
       0: aload_0       
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return        

  public void syncTask();
    Code:
       0: aload_0       
       1: dup           
       2: astore_1      
       3: monitorenter          "加锁"
       4: aload_0       
       5: dup           
       6: getfield      #2                  // Field i:I
       9: iconst_1      
      10: iadd          
      11: putfield      #2                  // Field i:I
      14: aload_1               "锁退出"
      15: monitorexit   
      16: goto          24
      19: astore_2      
      20: aload_1       
      21: monitorexit   
      22: aload_2       
      23: athrow        
      24: return        
    Exception table:
       from    to  target type
           4    16    19   any
          19    22    19   any
}
  • 结构
3: monitorenter          "加锁"
....
15: monitorexit    "锁退出"
16: goto          24
...     
21: monitorexit   
posted on 2024-06-19 22:01  学游者  阅读(15)  评论(0)    收藏  举报