Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >面试官问:多线程同步内部如何实现的,你知道怎么回答吗?

面试官问:多线程同步内部如何实现的,你知道怎么回答吗?

原创
作者头像
李红
修改于 2019-07-23 10:15:01
修改于 2019-07-23 10:15:01
1.1K00
代码可运行
举报
文章被收录于专栏:Java程序猿部落Java程序猿部落
运行总次数:0
代码可运行

线程同步可以说在日常开发中是用的很多, 但对于其内部如何实现的,一般人可能知道的并不多。 本篇文章将从如何实现简单的锁开始,介绍linux中的锁实现futex的优点及原理,最后分析java中同步机制如wait/notify, synchronized, ReentrantLock。

自己实现锁

首先,如果要你实现操作系统的锁,该如何实现?先想想这个问题,暂时不考虑性能、可用性等问题,就用最简单、粗暴的方式。当你心中有个大致的思路后,再接着往下看。

下文中的代码都是伪代码。

自旋

最容易想到可能是自旋:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
volatile int status=0;

void lock(){
	
	while(!compareAndSet(0,1)){
	}
	//get lock

}

void unlock(){
	status=0;
}

boolean compareAndSet(int except,int newValue){
	//cas操作,修改status成功则返回true
}

上面的代码通过自旋和cas来实现一个最简单的锁。

这样实现的锁显然有个致命的缺点:耗费cpu资源。没有竞争到锁的线程会一直占用cpu资源进行cas操作,假如一个线程获得锁后要花费10s处理业务逻辑,那另外一个线程就会白白的花费10s的cpu资源。(假设系统中就只有这两个线程的情况)。

yield+自旋

要解决自旋锁的性能问题必须让竞争锁失败的线程不忙等,而是在获取不到锁的时候能把cpu资源给让出来,说到让cpu资源,你可能想到了yield()方法,看看下面的例子:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
volatile int status=0;

void lock(){
	
	while(!compareAndSet(0,1)){
		yield();
	}
	//get lock

}

void unlock(){
	status=0;
}

当线程竞争锁失败时,会调用yield方法让出cpu。需要注意的是该方法只是当前让出cpu,有可能操作系统下次还是选择运行该线程。其实现是 将当期线程移动到所在优先调度队列的末端(操作系统线程调度了解一下?有时间的话,下次写写这块内容)。也就是说,如果该线程处于优先级最高的调度队列且该队列只有该线程,那操作系统下次还是运行该线程。

自旋+yield的方式并没有完全解决问题,当系统只有两个线程竞争锁时,yield是有效的。但是如果有100个线程竞争锁,当线程1获得锁后,还有99个线程在反复的自旋+yield,线程2调用yield后,操作系统下次运行的可能是线程3;而线程3CAS失败后调用yield后,操作系统下次运行的可能是线程4... 假如运行在单核cpu下,在竞争锁时最差只有1%的cpu利用率,导致获得锁的线程1一直被中断,执行实际业务代码时间变得更长,从而导致锁释放的时间变的更长。

sleep+自旋

你可能从一开始就想到了,当竞争锁失败后,可以将用Thread.sleep将线程休眠,从而不占用cpu资源:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
volatile int status=0;

void lock(){
	
	while(!compareAndSet(0,1)){
		sleep(10);
	}
	//get lock

}

void unlock(){
	status=0;
}

上述方式我们可能见的比较多,通常用于实现上层锁。该方式不适合用于操作系统级别的锁,因为作为一个底层锁,其sleep时间很难设置。sleep的时间取决于同步代码块的执行时间,sleep时间如果太短了,会导致线程切换频繁(极端情况和yield方式一样);sleep时间如果设置的过长,会导致线程不能及时获得锁。因此没法设置一个通用的sleep值。就算sleep的值由调用者指定也不能完全解决问题:有的时候调用锁的人也不知道同步块代码会执行多久。

park+自旋

那可不可以在获取不到锁的时候让线程释放cpu资源进行等待,当持有锁的线程释放锁的时候将等待的线程唤起呢?

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
volatile int status=0;

Queue parkQueue;

void lock(){
	
	while(!compareAndSet(0,1)){
		//
		lock_wait();
	}
	//get lock

}

void synchronized  unlock(){
	lock_notify();
}

void lock_wait(){
	//将当期线程加入到等待队列
	parkQueue.add(nowThread);
	//将当期线程释放cpu
	releaseCpu();
}
void lock_notify(){
	//得到要唤醒的线程
	Thread t=parkList.poll();
	//唤醒等待线程
	wakeAThread(t);
}

上面是伪代码,描述这种设计思想,至于释放cpu资源、唤醒等待线程的的具体实现,后文会再说。这种方案相比于sleep而言,只有在锁被释放的时候,竞争锁的线程才会被唤醒,不会存在过早或过完唤醒的问题。

小结

对于锁冲突不严重的情况,用自旋锁会更适合,试想每个线程获得锁后很短的一段时间内就释放锁,竞争锁的线程只要经历几次自旋运算后就能获得锁,那就没必要等待该线程了,因为等待线程意味着需要进入到内核态进行上下文切换,而上下文切换是有成本的并且还不低,如果锁很快就释放了,那上下文切换的开销将超过自旋。

目前操作系统中,一般是用自旋+等待结合的形式实现锁:在进入锁时先自旋一定次数,如果还没获得锁再进行等待。

futex

linux底层用futex实现锁,futex由一个内核层的队列和一个用户空间层的atomic integer构成。当获得锁时,尝试cas更改integer,如果integer原始值是0,则修改成功,该线程获得锁,否则就将当期线程放入到 wait queue中(即操作系统的等待队列)。

上述说法有些抽象,如果你没看明白也没关系。我们先看一下没有futex之前,linux是怎么实现锁的。

futex诞生之前

在futex诞生之前,linux下的同步机制可以归为两类:用户态的同步机制 和内核同步机制。 用户态的同步机制基本上就是利用原子指令实现的自旋锁。关于自旋锁其缺点也说过了,不适用于大的临界区(即锁占用时间比较长的情况)。

内核提供的同步机制,如semaphore等,使用的是上文说的自旋+等待的形式。 它对于大小临界区和都适用。但是因为它是内核层的(释放cpu资源是内核级调用),所以每次lock与unlock都是一次系统调用,即使没有锁冲突,也必须要通过系统调用进入内核之后才能识别。

理想的同步机制应该是没有锁冲突时在用户态利用原子指令就解决问题,而需要挂起等待时再使用内核提供的系统调用进行睡眠与唤醒。换句话说,在用户态的自旋失败时,能不能让进程挂起,由持有锁的线程释放锁时将其唤醒? 如果你没有较深入地考虑过这个问题,很可能想当然的认为类似于这样就行了(伪代码):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void lock(int lockval) {
	//trylock是用户级的自旋锁
	while(!trylock(lockval)) {
		wait();//释放cpu,并将当期线程加入等待队列,是系统调用
	}
}

boolean trylock(int lockval){
	int i=0; 
	//localval=1代表上锁成功
	while(!compareAndSet(lockval,0,1)){
		if(++i>10){
			return false;
		}
	}
	return true;
}

void unlock(int lockval) {
	 compareAndSet(lockval,1,0);
	 notify();
}

上述代码的问题是trylock和wait两个调用之间存在一个窗口: 如果一个线程trylock失败,在调用wait时持有锁的线程释放了锁,当前线程还是会调用wait进行等待,但之后就没有人再将该线程唤醒了。

futex诞生之后

我们来看看futex的方法定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	 //uaddr指向一个地址,val代表这个地址期待的值,当*uaddr==val时,才会进行wait
	 int futex_wait(int *uaddr, int val);
	 //唤醒n个在uaddr指向的锁变量上挂起等待的进程
	 int futex_wake(int *uaddr, int n);

futex_wait真正将进程挂起之前会检查addr指向的地址的值是否等于val,如果不相等则会立即返回,由用户态继续trylock。否则将当期线程插入到一个队列中去,并挂起。

futex内部维护了一个队列,在线程挂起前会线程插入到其中,同时对于队列中的每个节点都有一个标识,代表该线程关联锁的uaddr。这样,当用户态调用futex_wake时,只需要遍历这个等待队列,把带有相同uaddr的节点所对应的进程唤醒就行了。

作为优化,futex维护的其实是个类似java 中的concurrent hashmap的结构。其持有一个总链表,总链表中每个元素都是一个带有自旋锁的子链表。调用futex_wait挂起的进程,通过其uaddr hash到某一个具体的子链表上去。这样一方面能分散对等待队列的竞争、另一方面减小单个队列的长度,便于futex_wake时的查找。每个链表各自持有一把spinlock,将"*uaddr和val的比较操作"与"把进程加入队列的操作"保护在一个临界区中。 另外,futex是支持多进程的,当使用futex在多进程间进行同步时,需要考虑同一个物理内存地址在不同进程中的虚拟地址是不同的。

End

本文讲述了实现锁的几种形式以及linux中futex的实现,下篇文章会讲讲Java中ReentrantLock,包括其java层的实现以及使用到的LockSupport.park的底层实现。

原文:Java架构笔记

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
斯坦福报告展望2030年的人工智能与生活
2016年9月6日,斯坦福大学发布了一份名为《2030年的人工智能与生活》的研究报告,展望了人工智能的研究趋势以及2030年的人工智能与生活,主要内容如下: 1. 人工智能研究趋势 推动人工智能革命的研究工作正在快速发生变化,其中最重要的是机器学习技术的成熟,部分刺激来自于数字经济的崛起,因为它同时提供和利用了大量的数据。其他因素包括云计算资源的崛起和消费者对广泛接入服务的需求,如语音识别和导航支持。机器学习得到了来自人工神经网络的极大推动,而后者取得了令人印象深刻的成功经验,现在已经可以利用巨大的数据集和
人工智能快报
2018/03/07
1.3K0
斯坦福最新发布首份AI100报告,2030年我们的生活会是什么样子?
雷锋网注:斯坦福近期发起了名为“人工智能研究的100年”的项目, 制定了相关具体的计划(下个100年中每五年人工智能对社会影响的详细报告)。 AI研究趋势 千禧之年以前,人工智能(AI)的吸引力大部分
AI科技评论
2018/03/07
8110
斯坦福最新发布首份AI100报告,2030年我们的生活会是什么样子?
ChatGPT破圈的「秘密武器」:详解RLHF如何影响人类社会!
---- 新智元报道   来源:学术头条 编辑:好困 【新智元导读】机器能像人类一样思考吗?如果可以,人类应该如何教育机器? 1950 年,Alan Turing 提出,我们应该「以教育孩子的方式来教育机器」「为机器提供金钱可以买到的最好的感觉器官,然后再教育它……」;1959 年,John McCarthy 提出了一个如此系统的最早迭代,描述了一个「建议接受者」,它可以通过常识推理进行学习,从任何一组作为命令性语句发布给系统的前提中得出逻辑性的结论。 20 世纪 80 年代,Hayes-Roth 等
新智元
2023/03/29
3810
ChatGPT破圈的「秘密武器」:详解RLHF如何影响人类社会!
联合国教科文组织首份《人工智能伦理建议书》发布
  《人工智能伦理建议书》明确了规范人工智能技术的10大原则和11个行动领域,是迄今为止全世界在政府层面达成的最广泛的共识,是全球人工智能发展的共同纲领,并将为进一步形成人工智能有关的国际标准、国际法等提供强有力的参考。
新智元
2021/12/13
4490
五年磨一剑:李飞飞AI100报告第二弹,提出14大AI机遇与挑战
本次报告评估了2016年至2021年间人工智能的发展,涵盖14大问题,探讨了人工智能发展的关键领域。
新智元
2021/10/12
3950
普华永道重磅报告:15.7万亿美元AI市场的八大入口
本次,我们推荐来普华永道的达沃斯报告——《衡量人工智能所带来的影响:把握机遇》,从经济体和产业的角度阐述人工智能即将创造的商机,并推出“人工智能影响指数”,分析八大商业领域的近300个用例。
IT阅读排行榜
2018/08/16
4580
普华永道重磅报告:15.7万亿美元AI市场的八大入口
科技巨头将组AI界的“正义者联盟”,but你们的苹果不参与
人工智能的浪潮已经席卷了各个行业,并取得了一系列突破性进展,从语音识别的工具到无人驾驶汽车,再到可自动作战的新一代武器系统等,将人类的生活水平、科技发展带上了一个前所未有的新高度。但与此同时,“威胁论
AI科技评论
2018/03/07
7120
科技巨头将组AI界的“正义者联盟”,but你们的苹果不参与
国务院印发:新一代人工智能发展规划
国务院关于印发 新一代人工智能发展规划的通知 国务院         2017年7月8日       新一代人工智能发展规划 人工智能的迅速发展将深刻改变人类社会生活、改变世界。为抢抓人工智能发展的重大战略机遇,构筑我国人工智能发展的先发优势,加快建设创新型国家和世界科技强国,按照党中央、国务院部署要求,制定本规划。 一、战略态势 人工智能发展进入新阶段。经过60多年的演进,特别是在移动互联网、大数据、超级计算、传感网、脑科学等新理论新技术以及经济社会发展强烈需求的共同驱动下,人工智能加速发展,呈现出深度学
小莹莹
2018/04/20
9180
政策、监管与规制:《联合国的人工智能政策》解读
  中国信息通信研究院与腾讯研究院AI联合课题组   作  者:Danit Gal  腾讯研究院科技政策分析师   译  者:孙   那  腾讯研究院研究员、博士后              李金磊  腾讯研究院助理研究员   人工智能是人类进入信息产业革命时代,达到的认识和改造客观世界能力的高峰。人工智能的大规模应用与机器人技术发展的日新月异,将在未来带给人类社会前所未有的巨大冲击。联合国作为全球最重要的国际组织,在2016年最新发布的人工智能报告中,表达了其对于人工智能的关注;同时为应对人工智能
腾讯研究院
2018/02/01
9200
政策、监管与规制:《联合国的人工智能政策》解读
【钱塘号专栏】中国工程院院刊:人工智能2.0时代序幕开启
【导读】中国科学技术部 “科技创新2030—重大项目”近期或将新增“人工智能2.0”,人工智能将进一步上升为国家战略。近日,中国工程院院刊信息与电子工程学部分刊《信息与电子工程前沿(英文)》出版了“Artificial Intelligence 2.0”专题,潘云鹤、李未、高文、郑南宁、吴澄、李伯虎、陈纯等多位院士以及专家学者参与撰文,对人工智能2.0中所涉及的大数据智能、群体智能、跨媒体智能、混合增强智能和自主智能等进行了深度阐述。 中国“科技创新2030 重大项目”将新增“人工智能2.0” 根据中新网的
钱塘数据
2018/03/05
1.1K0
【钱塘号专栏】中国工程院院刊:人工智能2.0时代序幕开启
斯坦福以人为本AI研究院成立,李飞飞任联合主任
数月前,斯坦福教授李飞飞和前教务长John Etchemendy共同主导的“以人为本人工智能研究院(Stanford Human-Centered AI Institute)”项目宣布启动。
新智元
2019/05/08
7140
斯坦福以人为本AI研究院成立,李飞飞任联合主任
震撼 | 霍金:AI或带来人类文明终结
GMIC 2017 北京大会于4月27日在国家会议中心拉开帷幕。大会以“天·工·开·悟”为主题,上午领袖论坛首场Keynote由霍金带来。霍金先生通过视频的方式对现场观众做了题为《让人工智能造福人类及其赖以生存的家园》的演讲,他对未来人工智能过度发展可能带来的负面影响表达了担忧,同时也和与会者探讨了关于未来是否要为人工智能赋予“人格”以期限定其权利责任问题。视频最后,霍金回答了李开复和傅盛等业内领袖与网友的问题。 早先,霍金老爷子也难得地在微博发文,为自己的Keynote预热。 演讲中霍金被问及如果
小莹莹
2018/04/19
6280
震撼 | 霍金:AI或带来人类文明终结
未来已来,揭秘未来人工智能八大趋势
从计算上来讲,大数据分析这股潮流并不会像流星那样转瞬即逝。随着数据量的不断增加,对大数据分析的改进也不会停止。对于预测分析方面的应用,我们只看到了冰山一角。 一些机构正在使用数据挖掘、机器学习和人工智能技术来分析当前的数据以求更好地开展业务(例如预测销售情况、优化营销活动等)。所有这些不同类型的人工智能技术已紧密地结合在一起,改变了我们的日常生活,而且这种改变仍将持续。 以下是人工智能、大数据、预测分析和机器学习方面主要的统计数据: 到2018年,75%的开发人员将在一个或多个业务应用或服务中采用人工智能技
钱塘数据
2018/03/06
8620
未来已来,揭秘未来人工智能八大趋势
ChatGPT 之优势与缺陷
欢迎来到《ChatGPT:好的、坏的和丑陋的》。在本书中,我们踏上了探索 ChatGPT 多面世界的旅程,这是由 OpenAI 开发的先进自然语言处理模型。随着 ChatGPT 和类似的人工智能技术不断发展并影响我们生活的各个方面,了解它们的潜力、局限性和道德影响至关重要。本书旨在全面探讨 ChatGPT 的好的、坏的和丑陋的方面,揭示其革命性进展、潜在陷阱以及它所带来的复杂挑战。
ApacheCN_飞龙
2024/05/24
1380
【重磅研报】中国人工智能产业链三大投资蓝海详解
【新智元导读】这两天人工智能分外火爆,乐视推出超级大脑,猎豹投入5000万美金研发机器人。在中信证券这篇长达1.5万字的人工智能产业投资研究报告里,分析师冷静而严谨地看好深度学习、图像识别和智能机器人这三片投资蓝海。报告认为,历史上人工智能的投资如果在应用层出现泡沫,未来的机会往往在技术层。中信证券的秦培景博士昨天在中信证券与新智元联合举办的人工智能产业研讨会上说:“未来人工智能这片蓝海怎么去航行?可以说是技术为锚,资本为帆,但是如果我们没有把握这个航线的话,创业的小船也是说翻就翻。” 【秦培景等】从二十
新智元
2018/03/21
1.7K0
【重磅研报】中国人工智能产业链三大投资蓝海详解
AI 公共政策成全球热点,美国 ITI 发布《人工智能政策原则》
作者:曹建峰 腾讯研究院法律研究中心高级研究员   祝林华 腾讯研究院法律研究中心助理研究员 一、 AI公共政策成AI领域全球热点 AI研究开发和行业应用的热度仍在持续,在此背景下,A
腾讯研究院
2017/11/02
1.8K0
报告分享|2022年人工智能行业研究最新动态
随着人工智能技术发展步入快车道,业务数量和覆盖面不断提升,新业务模式和新 产品持续涌现。人工智能行业这些热点值得关注:
拓端
2022/11/09
1.2K0
教育部印发《高校人工智能创新行动计划》, 500万AI人才缺口要补上!
【新智元导读】教育部日前印发了《高等学校人工智能创新行动计划》,提出18项重点任务,并制定“三步走规划”:首先到2020年完善学科体系,到2025年取得一批有国际影响力的原创成果,到2030年让高校成为建设世界主要人工智能创新中心的核心力量,为我国跻身创新型国家前列提供科技支撑和人才保障。《行动计划》发布后将对高校和今后中国人工智能发展产生什么影响?本文带来专家权威解读。 据西安电子科技大学官网消息,4月2日,教育部印发了《高等学校人工智能创新行动计划》(下称《行动计划》)。这是教育领域落实国务
新智元
2018/04/17
1.2K0
教育部印发《高校人工智能创新行动计划》, 500万AI人才缺口要补上!
假期错过的...条AI新闻都在这里了
本期一周AI看点包括行业资讯、投融资、业界观点、技术前沿以及应用等方面。 行业 苹果悄然收购 Init.ai 公司,为 Siri 增加研发实力 Init.ai公司以其客户服务自动化而闻名,只有6个人的规模。他们打造的客户服务智能助手可以从与用户的互动中分析并获得更好的见解,并自动化一些互动行为。苹果在WWDC 上宣布了一项名为“商业聊天”的iOS 11新功能。Init.ai团队也将帮助完成这个功能。 IBM公司推动AI便携化:海浪预测系统可运行在Raspberry Pi设备之上 IBM公司的研究人员们已
AI科技大本营
2018/04/28
7000
假期错过的...条AI新闻都在这里了
五大因素推动中国AI崛起,生态报告概览中国AI产业
选自 vertex 机器之心编译 参与:机器之心编辑部 中国的人工智能将会在全世界扮演什么样的角色?最近,风险投资机构Vertex发表了一份生态研究报告,从业内、技术、政策和投资等角度预测了中国未来AI领域的发展。报告认为,中国将会很快成为全球人工智能技术的中心。完整 pdf 见文后。 一、中国AI崛起五大因素 五大因素促使中国发展成为全球 AI 中心:(1)多个行业希望利用 AI 实现数字化转型;(2)大量人工智能高端人才;(3)移动互联网市场前景广阔;(4)高性能计算技术;(5)政府政策支持。其中,前两
机器之心
2018/05/09
7260
五大因素推动中国AI崛起,生态报告概览中国AI产业
推荐阅读
相关推荐
斯坦福报告展望2030年的人工智能与生活
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验