Java程序员必会Synchronized底层原理剖析

网站建设4年前发布
65 0 0

synchronized作为Java程序员最常用同步工具,很多人却对它的用法和实现原理一知半解,以至于还有不少人认为synchronized是重量级锁,性能较差,尽量少用。,但不可否认的是synchronized依然是并发首选工具,连volatile、CAS、ReentrantLock都无法动摇synchronized的地位。synchronized是工作面试中的必备技能,今天就跟着一灯一块深入剖析synchronized的底层原理。,synchronized是Java提供一种隐式锁,无需开发者手动加锁释放锁。保证多线程并发情况下数据的安全性,实现了同一个时刻只有一个线程能访问资源,其他线程只能阻塞等待,简单说就是互斥同步。,先看一下synchronized有哪几种用法?,可以看到被锁对象只要有两种,实例对象和class类。,当我们使用synchronized在方法和对象上加锁的时候,Java底层到底怎么实现加锁的?,当在类对象上加锁的时候,也就是在class类加锁,代码如下:,反编译一下,看一下源码实现:,2023030613570019f7db1753aac2307ae2620c38f14f474a531b288,可以看到,底层是通过monitorenter和monitorexit两个关键字实现的加锁与释放锁,执行同步代码之前使用monitorenter加锁,执行完同步代码使用monitorexit释放锁,抛出异常的时候也是用monitorexit释放锁。,写成伪代码,类似下面这样:,当在实例方法上加锁,底层是怎么实现的呢?代码如下:,再反编译看一下底层实现:,20230306135701f236d902816cf9f99d5137e5486ea4990f3ccc912,这次只使用了一个ACC_SYNCHRONIZED关键字,实现了隐式的加锁与释放锁。其实无论是ACC_SYNCHRONIZED关键字,还是monitorenter和monitorexit,底层都是通过获取monitor锁来实现的加锁与释放锁。,而monitor锁又是通过ObjectMonitor来实现的,虚拟机中ObjectMonitor数据结构如下(C++实现的):,20230306135701f82b9e123e0398a16c578804d66adc49ada5b1743,图上展示了ObjectMonitor的基本工作机制:,当多个线程同时访问一段同步代码时,首先会进入 _EntryList 队列中等待。,当某个线程获取到对象的Monitor锁后进入临界区域,并把Monitor中的 _owner 变量设置为当前线程,同时Monitor中的计数器 _count 加1。即获得对象锁。,若持有Monitor的线程调用 wait() 方法,将释放当前持有的Monitor锁,_owner变量恢复为null,_count减1,同时该线程进入 _WaitSet 集合中等待被唤醒。,在_WaitSet 集合中的线程会被再次放到_EntryList 队列中,重新竞争获取锁。,若当前线程执行完毕也将释放Monitor并复位变量的值,以便其他线程进入获取锁。,线程争抢锁的过程要比上面展示得更加复杂。除了_EntryList 这个双向链表用来保存竞争的线程,ObjectMonitor中还有另外一个单向链表 _cxq,由两个队列来共同管理并发的线程。,202303061357015382e7093833a5db84b472007391a7ea0343ad805

© 版权声明

相关文章