600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Java并发编程-synchronized底层原理

Java并发编程-synchronized底层原理

时间:2020-09-06 02:15:31

相关推荐

Java并发编程-synchronized底层原理

synchronized底层原理与Monitor密切相关

1.Java对象头

以 32 位虚拟机为例

普通对象

对象的类型,如Student类型,Teacher类型等是由KlassWord来表示的,它是一个指针,指向了对象所从属的Class。即找到类。

其中 Mark Word 结构为

其中,age表示垃圾回收时的分代年龄,具体可见分代收集算法。年龄超过一定岁数就从幸存区调入到老年代。最后两位,biased_lock和01表示偏向锁和加锁状态。其它表示在不同状态下每一位所代表的含义。Normal状态表示对象的正常状态。对它加各种所的时候,其值通常会改变。

数组对象

注意:所以,这里我们也可以想到,在一个Integer对象里,要保存8个字节的对象头,还有4个字节的int类型的数据。总共12字节,而基本数据类型int则只需4个字节。在内存敏感的情况下,建议用基本类型。

2.Monitor(锁)工作原理

synchronized底层原理可以用Monitor工作原理来解释

Monitor被翻译为监视器或者管程

每个 Java 对象都可以关联一个 Monitor 对象,如果使用 synchronized 给对象上锁(重量级)之后,该对象头的

Mark Word 中就被设置指向 Monitor 对象的指针

当我们线程2执行如下代码时:

synchronized(this){//处理相关业务}

1.Thread2线程执行上述代码时,当前对象this会被上一把锁,这是一把重量级锁,this对象头的Mark Word字段指向了操作系统创建的Monitor对象引用地址

MarkWord在没有加任何锁的时候,即Normal状态,标记位为01,一旦获取了锁,就会尝试找一个monitor与之关联,然后把最后两位也即标记位从01改为10,并且把前面的所有位改成指向monitor对象的指针,占用30位。此时由于只有Thread2线程,所以成功获取了锁。理所应当的成为了monitor对象的owner。

owner表示Monitor锁的持有者,而且同一个时刻只能有一个owner

2.Monitor对象只能有一个owner,此时如果有其它线程如Thread-3或Thread-4等线程要获取这把锁就要进入Monitor对象的堵塞队列EntryList中等待Thread2释放锁

EntryList可以理解位阻塞队列或等待队列。一直等待到其它线程释放了owner的所有权

3.等待锁资源被释放后,Thread-3或Thread-4会互相竞争锁资源,并不能保证谁获取到锁,最终还是有CPU来决定

4.Monitor对象的WaitSet存放的是,获取到锁的线程,但是由于其它一些原因导致线程进入Waiting状态,又释放了锁资源,待介绍

同样地,对于下图

1.刚开始 Monitor 中 Owner 为 null

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

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

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

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

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

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

3.字节码角度理解synchronized底层工作原理

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

反编译成字节码,具体反编译过程及字节码指令介绍可以参看JVM学习-字节码指令

字节码如下:

public static void main(java.lang.String[]);descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=3, args_size=10: getstatic#2 //<-lock引用(synchronized开始)3: dup4: astore_1 //lock引->slot15: monitorenter //将lock对象Markword置为monitor指针6: getstatic#3 // Field counter:I9: iconst_110: iadd11: putstatic#3 // Field counter:I14: aload_1 //<-lock引用,拿到刚开astore1刚才存储的临时变量15: monitorexit //将lock对象MarkWord重置,唤醒EntryList.重新设置markword其它字段,让entryList中正在等待的线程竞争锁16: goto24 /*如果同步代码块中发生了异常,然后就处理下列代码,即19-23行。最下面的Exception table表第一行时监测6-16行是否发生了异常,即同步代码块中的代码。如果发生了异常,就跳转到19行执行。先把异常对象存储进来,然后根据对象引用地址找到monitor,然后也是做一些善后的工作。把monitor中的状态还原,并唤醒entrylist中的其它线程*/19: astore_220: aload_121: monitorexit22: aload_223: athrow24: returnException table:from to target type6 16 19 any19 22 19 any

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。