Synchronized 实现原理

synchronized

锁定某个对象,才能访问某段代码
public class SynchronizedTest {

    static Object lock = new Object();
    static List<Integer> list = new ArrayList<>(10);

    public static void main(String[] args) {
        synchronized (lock) {
            list.add(1);
        }
    }
}

字节码实现(编译层面):通过monitorentermonitorexit 实现互斥

 0 getstatic #2 <com/devin/jmm/SynchronizedTest.lock : Ljava/lang/Object;>
 3 dup
 4 astore_1
 5 monitorenter
 6 getstatic #3 <com/devin/jmm/SynchronizedTest.list : Ljava/util/List;>
 9 iconst_1
10 invokestatic #4 <java/lang/Integer.valueOf : (I)Ljava/lang/Integer;>
13 invokeinterface #5 <java/util/List.add : (Ljava/lang/Object;)Z> count 2
18 pop
19 aload_1
20 monitorexit
21 goto 29 (+8)
24 astore_2
25 aload_1
26 monitorexit
27 aload_2
28 athrow
29 return

在这里插入图片描述

为什么存在两个monitorexit

同步代码块中发生异常时,synchronized自动解锁

JVM层级(Hotspot)

在对象上加锁,锁定的是对象

锁升级的过程

JDK较早版本:使用OS的资源互斥量实现,经历“用户态” -> “内核态”,属于重量级操作,效率比较低

现代版本进行了优化

无锁 -> 偏向锁 -> 轻量级锁(自旋锁)-> 重量级锁
在这里插入图片描述
在这里插入图片描述

无锁 -> 偏向锁
在这里插入图片描述
偏向锁 - markword 上记录当前线程指针(线程id),下次同一个线程加锁的时候,不需要竞争,只需要判断线程指针是否同一个,所以偏向锁偏向加锁的第一个线程,hashCode备份在线程栈上,线程销毁时,锁降级为无锁

偏向锁被争用 - 升级为轻量级锁
在这里插入图片描述
每个线程存放LockRecord在自己的线程栈上,用CAS去争用markword的LR的指针,指针指向哪个线程,哪个线程就获得了轻量级锁
在这里插入图片描述

轻量级锁自旋次数超过10次,升级为重量级锁

如果太多线程自旋 CPU消耗过大,不如升级为重量级锁,进入对象的等待队列(不消耗CPU)

重量级锁的实现,生成一个C++层面的monitor对象,markword指向这个monitor对象(互斥量),monitor提供一个阻塞队列,竞争锁的线程入队等待,由CPU调度决定获取重量级锁的线程

在这里插入图片描述

偏向锁由于有锁撤销的过程revoke,会消耗系统资源,所以,在锁争用特别激烈的时候,用偏向锁未必效率高,还不如直接使用轻量级锁(-XX:-useBiasedLocking)

synchronized VS Lock(CAS)

在高争用,高耗时的环境下synchronized效率更高
在低争用,低耗时的环境下CAS效率更高
synchronized到重量级之后是等待队列(不消耗CPU)
CAS(等待期间消耗CPU)    

synchronized的CPU层面实现

使用 lock + comxchg 实现

    comxchg: CAS获取锁
    lock: 执行代码块的时候,其他CPU不能访问该内存区域   
`synchronized` 是 Java 中用于实现线程同步的关键字,它可以用来修饰代码块或方法。当某个线程执行一个被 `synchronized` 修饰的代码块或方法时,它会尝试获取对象的锁(monitor),如果锁没有被其他线程占用,则该线程会获取到锁,并继续执行代码块或方法;如果锁已经被其他线程占用,则该线程会被阻塞,直到获取到锁为止。 `synchronized` 的实现原理可以分为以下几个步骤: 1. 当一个线程尝试获取某个对象的锁时,它会先检查锁是否被其他线程占用。 2. 如果锁未被占用,则该线程会获取到锁,并继续执行代码块或方法。 3. 如果锁已经被其他线程占用,则该线程被阻塞,并被放入对象的等待队列中。 4. 当锁被释放时,等待队列中的线程会被唤醒,然后再次尝试获取锁。 5. 如果此时有多个线程都被唤醒,则它们会竞争获取锁,只有一个线程能够获取到锁,其他线程仍然被阻塞。 在 `synchronized` 中,锁是以对象为单位的。每个对象都有一个与之关联的锁,称为对象的监视器(monitor)。当一个线程进入某个对象的 `synchronized` 代码块或方法时,它会尝试获取该对象的监视器。如果监视器未被其他线程占用,则该线程获取到监视器并继续执行代码块或方法;如果监视器已经被其他线程占用,则该线程被阻塞,直到获取到监视器为止。当代码块或方法执行完毕后,该线程会释放监视器。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值