多线程教程(七)monitor概念、synchronized原理浅析

多线程教程(七)monitor概念

一、Java 对象头

java对象通常在内存中主要由两部分组成,一是对象头,另一部分是对象中的成员变量。

以 32 位虚拟机为例,对象头如下所示:

(1)普通对象

|--------------------------------------------------------------| 
|						 Object Header (64 bits) 			   |
|------------------------------------|-------------------------|
| 	Mark Word (32 bits) 			 |	 Klass Word (32 bits)  |
|------------------------------------|-------------------------|

klass word 部分表示类的类型,它是个指针,指向对象对应的class

(2)数组对象

|-------------------------------------------------------------------------|
|					    Object Header (96 bits) 						  |
|-----------------------|------------------------|------------------------|
|   Mark Word(32bits) 	|	 Klass Word(32bits)  | 	array length(32bits)  |
|-----------------------|------------------------|------------------------|

(3)其中 Mark Word 结构为

|----------------------------------------------------|--------------------|
| 			Mark Word (32 bits)						 | 		State 		  |
|----------------------------------------------------|--------------------|
| hashcode:25 	| age:4 	| biased_lock:0 	| 01 | 		Normal		  |
|----------------------------------------------------|--------------------|
| thread:23   | epoch:2 | age:4 | biased_lock:1 | 01 |	    Biased 		  |
|----------------------------------------------------|--------------------|
| 		ptr_to_lock_record:30 					| 00 | Lightweight Locked |
|----------------------------------------------------|--------------------|
|		 ptr_to_heavyweight_monitor:30 			| 10 | Heavyweight Locked |
|----------------------------------------------------|--------------------|
| 												| 11 | 	 Marked for GC 	  |
|----------------------------------------------------|--------------------|

64 位虚拟机 Mark Word

|-------------------------------------------------------|-----------------|
| 					Mark Word (64 bits)				 	| 		State 	  |
|-------------------------------------------------------|-----------------|
|unused:25|hashcode:31|unused:1|age:4|biased_lock:0| 01 | 		Normal    |
|-------------------------------------------------------|-----------------|
| thread:54 | epoch:2 |unused:1|age:4|biased_lock:1| 01 | 		Biased    |
|-------------------------------------------------------|-----------------|
| 			ptr_to_lock_record:62 			       | 00 |LightweightLocked|
|-------------------------------------------------------|-----------------|
| 		ptr_to_heavyweight_monitor:62			   | 10 |HeavyweightLocked|
|-------------------------------------------------------|-----------------|
| 												   | 11 |  Marked for GC  |
|-------------------------------------------------------|-----------------|
二、monitor原理

Monitor 被翻译为监视器管程

每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的Mark Word 中就被设置指向 Monitor 对象的指针

偏向锁和轻量级锁是不会关联Monitor的,具体原理后续章节(可能放在锁升级章节)会进行介绍

Monitor 结构如下

在这里插入图片描述

刚开始 Monitor 中 Owner 为 null

  1. 当 Thread-2 执行 synchronized(obj) 就会将 Monitor 的所有者 Owner 置为 Thread-2,Monitor中只能有一个 Owner

  2. 在 Thread-2 上锁的过程中,如果 Thread-3,Thread-4,Thread-5 也来执行 synchronized(obj),就会进入EntryList,状态变为 BLOCKED

  3. Thread-2 执行完同步代码块的内容,然后唤醒 EntryList 中等待的线程来竞争锁,竞争的时是非公平的

  4. 图中 WaitSet 中的 Thread-0,Thread-1 是之前获得过锁,但条件不满足进入 WAITING 状态的线程,后面讲wait-notify 时会分析

简单点说waitSet里面就是拿到过这个锁的线程执行wait后会释放锁,进入waitset,等待后续拿到这个锁的线程执行notify或notifyall来激活在waitSet里的线程。

该方法常用来等待指定线程产生结果后继续执行。

注意:

synchronized 必须是进入同一个对象的 monitor 才有上述的效果

不加 synchronized 的对象不会关联监视器,不遵从以上规则

三、synchronized 原理

执行下属代码

static final Object lock = new Object();
static int counter = 0;
public static void main(String[] args) {
     synchronized (lock) {
     	counter++;
     }
}

对应的字节码:

public static void main(java.lang.String[]);
 descriptor: ([Ljava/lang/String;)V
 flags: ACC_PUBLIC, ACC_STATIC
 Code:
     stack=2, locals=3, args_size=1
         0: getstatic #2 // <- lock引用 (synchronized开始)
         3: dup
         4: astore_1 // lock引用 -> slot 1
         5: monitorenter // 将 lock对象 MarkWord 置为 Monitor 指针
         6: getstatic #3 // <- i
         9: iconst_1 // 准备常数 1
         10: iadd // +1
         11: putstatic #3 // -> i
         14: aload_1 // <- lock引用
         15: monitorexit // 将 lock对象 MarkWord 重置, 唤醒 EntryList
         16: goto 24
         19: astore_2 // e -> slot 2 
         20: aload_1 // <- lock引用
         21: monitorexit // 将 lock对象 MarkWord 重置, 唤醒 EntryList
         22: aload_2 // <- slot 2 (e)
         23: athrow // throw e
         24: return
     Exception table:
     	from to target type
     		6 16 19 any
     		19 22 19 any
     LineNumberTable:
         line 8: 0
         line 9: 6
         line 10: 14
         line 11: 24
     LocalVariableTable:
     	Start Length Slot Name Signature
     		0 25 0 args [Ljava/lang/String;
     StackMapTable: number_of_entries = 2
     	frame_type = 255 /* full_frame */
         offset_delta = 19
         locals = [ class "[Ljava/lang/String;", class java/lang/Object ]
         stack = [ class java/lang/Throwable ]
     	frame_type = 250 /* chop */
     		offset_delta = 4

注意

方法级别的 synchronized 不会在字节码指令中有所体现

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值