1.Synchronized锁
首先,synchronized的基本原理是基于对象头当中的监视器,因此它也叫做监视器锁。
将synchronized进行反编译后,会发现有一个moniter_enter命令和一个moniter_exit命令,前者是将对象头当中的计数器加1,后者是将对象头当中的计数器减1,当然,这是广义上的解释,接下来进行详细解释。
2.对象头
一个对象的对象头当中包含三个部分,mark_word,指向方法区中对象的引用,以及数组长度。
synchronized锁的原理主要在于mark_word部分。
3.Synchronized锁流程
mark_word当中的格式:

1.无锁时,对象头为普通对象头,前25位记录了对象的hashcode,锁标志位为01,是否偏向锁为0;
2.当对象被当作同步锁并且有一个线程抢到了锁时,锁的标志位还是01,但偏向锁变为1,前23位变成抢到该锁线程的id
3.当线程A再次试图来获得锁时,JVM发现同步锁对象的标志位是01,是否偏向锁是1,也就是偏向状态,Mark Word中记录的线程id就是线程A自己的id,表示线程A已经获得了这个偏向锁,可以执行同步锁的代码。
4.线程B试图获得这个锁时,JVM发现同步锁处于偏向状态,但是Mark Word中的线程id记录的不是B,那么线程B会先用CAS操作试图获得锁,这里的获得锁操作是有可能成功的,因为线程A一般不会自动释放偏向锁。如果抢锁成功,就把Mark Word里的线程id改为线程B的id,代表线程B获得了这个偏向锁,可以执行同步锁代码。如果抢锁失败,则执行步骤5
5.偏向锁状态抢锁失败,代表当前锁有一定的竞争,偏向锁将升级为轻量级锁。JVM会在当前线程的线程栈中开辟一块单独的空间,里面保存指向对象锁Mark Word的指针,同时在对象锁Mark Word中保存指向这片空间的指针。上述两个保存操作都是CAS操作,如果保存成功,代表线程抢到了同步锁,就把Mark Word中的锁标志位改成00,可以执行同步锁代码。如果保存失败,表示抢锁失败,竞争太激烈,继续执行步骤6。
6.轻量级锁抢锁失败,JVM会使用自旋锁,自旋锁不是一个锁状态,只是代表不断的重试,尝试抢锁。从JDK1.7开始,自旋锁默认启用,自旋次数由JVM决定。如果抢锁成功则执行同步锁代码,如果失败则继续执行步骤7。
7.自旋锁重试之后如果抢锁依然失败,同步锁会升级至重量级锁,锁标志位改为10。在这个状态下,未抢到锁的线程都会被阻塞。
本文详细解析了Java中的synchronized锁的工作原理,包括对象头的结构和锁的状态转换。从无锁到偏向锁、轻量级锁、重量级锁的升级过程,阐述了锁在不同状态下的行为,帮助读者深入理解Java同步机制。
460

被折叠的 条评论
为什么被折叠?



