synchronized关键字的底层原理?

程序员咋不秃头2024-03-16 01:10:17  80

在 Java 中,关键字 synchronized 可以保证在同一个时刻,只有一个线程可以执行某个方法或者某个代码块(主要是对方法或者代码块中存在共享数据的操作),同时我们还应该注意到 synchronized 的另外一个重要的作用,synchronized 可保证一个线程的变化(主要是共享数据的变化)被其他线程所看到

1. synchronized的基本使用

在现实场景中,抢票代码,如果不加锁,就会出现超卖或者一张票卖给多个人

Synchronized对象锁采用互斥的方式让同一时刻至多只有一个线程能持有对象锁,其它线程再想获取这个对象锁时就会阻塞住,代码如下

public class synchronizedTest { // 创建一个静态对象作为锁 static Object lock = new Object; // 初始票数 int ticketNum = 20; // 获取票的方法,使用 synchronized 修饰确保线程安全 public synchronized void getTicket { // 使用当前对象作为锁 synchronized (this) { // 如果票数已经为零,则返回 if (ticketNum <= 0) { return; } System.out.println(Thread.currentThread.getName + "抢到一张票,剩余:" + ticketNum); // 非原子性操作,扣除一张票 ticketNum--; } } public static void main(String[] args) { // 创建 synchronizedTest 实例 synchronizedTest synchronizedTest = new synchronizedTest; // 创建并启动 20 个线程 for (int i = 0; i < 20; i++) { // 调用获取票的方法 new Thread( -> synchronizedTest.getTicket).start; } }}

通过以上代码,加synchronized锁,就可以防止超卖

特别说明:synchronized 关键字的底层实现涉及到 Java 虚拟机中的监视器(Monitor)机制。每个 Java 对象都与一个 Monitor 相关联,Monitor 负责对象的锁定和解锁,以及线程的阻塞和唤醒。

2. Monitor

Monitor 被翻译为监视器,是由jvm提供,c++语言实现

使用一下简单代码中查看monitor,通过javap命令查看clsss的字节码

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

monitorenter: 上锁开始的地方

monitorexit: 解锁的地方

其中被monitorenter和monitorexit包围住的指令就是上锁的代码

思考:为什么会出现两个monitorexit

有两个monitorexit的原因,第二个monitorexit是为了防止锁住的代码抛异常后不能及时释放锁在使用了synchornized代码块时需要指定一个对象,所以synchornized也被称为对象锁

monitor主要就是跟这个对象产生关联,如下图

Monitor内部具体的存储结构:

Owner:存储当前获取锁的线程的,只能有一个线程可以获取

EntryList:关联没有抢到锁的线程,处于Blocked状态的线程

WaitSet:关联调用了wait方法的线程,处于Waiting状态的线程

具体的流程:

代码进入synchorized代码块,先让lock(对象锁)关联的monitor,然后判断Owner是否有线程持有

如果没有线程持有,则让当前线程持有,表示该线程获取锁成功

如果有线程持有,则让当前线程进入entryList进行阻塞,如果Owner持有的线程已经释放了锁,在EntryList中的线程去竞争锁的持有权(非公平)

如果代码块中调用了wait方法,则会进去WaitSet中进行等待

3.面试题

面试官:synchronized关键字的底层原理?

Synchronized【对象锁】采用互斥的方式让同一时刻至多只有一个线程能持有【对象锁】

它的底层由monitor实现的,monitor是jvm级别的对象( C++实现),线程获得锁需要使用对象(锁)关联monitor

在monitor内部有三个属性,分别是owner、entrylist、waitset

其中owner是关联的获得锁的线程,并且只能关联一个线程;entrylist关联的是处于阻塞状态的线程;waitset关联的是处于Waiting状态的线程

转载此文是出于传递更多信息目的。若来源标注错误或侵犯了您的合法权益,请与本站联系,我们将及时更正、删除、谢谢。
https://www.414w.com/read/15873.html
0
随机主题
史上成色最低的一场欧联决赛——看联赛排名, 冠军第5, 亚军第1420GB+256GB+1TB扩展, 顶配跌至999元, 蓝厂5G手机售价再创新低短剧头部演员接连病倒?张集骏输液近一月,申浩男吃药鹿单东养病电脑时间日期不自更新了怎么办?为什么每次开机时间都不对?G1东欧爆种, 不然想晋级都难? 森林狼绅士横扫独行侠不在话下刚在火箭试训中表现突出, 今又不希望加盟火箭。继续打压! 美国正式宣布8月起对中国电动汽车加征关税王红权星近三月直播13场销售额超2500万:卖每瓶3000元的洗发水听我的劝告: 早入手小米14 Pro的人别轻易看价格, 你会后悔神印王座: 龙皓晨晋升七阶, 圣采儿完成神眷觉醒, 阿宝被打败“我来雄安了! ”全国35家80余位媒体代表走进雄安通胀数据不及预期,英国降息的可能性正在逐渐消失实测电脑内存条DDR5的 7600能比6400频率提升多少帧 内存条避坑指南冈田武史调侃: 浙江队主场氛围非常好, 我执教时为何没这待遇?618不知道怎么入手数码产品? 这四款产品不容错过!辽宁男篮客场胜新疆,大比分3比0丛明晨凌晨4点发博庆祝夺冠: 兄弟们牛逼 纯纯躺赢郭德纲讽刺同行有多狠?相声没落全因同行太差劲跌倒6.25万, 可如今却混到没人要, 最失败的小钢炮突发! 2换1交易方案曝光: 乔治加盟公牛, 拉文驰援哈登小卡?客户生病,投保的保险没有理赔,去客户家道个歉
最新回复(0)