Redian新闻
>
应用层|关于编程语言中的那些「锁」事

应用层|关于编程语言中的那些「锁」事

公众号新闻

并发锁,在编程语言中并不陌生。不同的语言中,锁的使用大同小异,以 Java 语言中的锁最为典型。我们今天就从什么是锁、我们为什么需要锁、锁的分类、有关锁的应用这四个方面,一起来聊聊与锁有关的那些事。

什么是锁

在日常生活中,锁就是一个安全标志。我们通过上锁和解锁,实现安全离家和回家。在编程语言中,锁也是个安全标志。在多线程并发场景下,给某个变量,或某个方法函数加个锁,代表同一时刻只能有一个线程访问该变量或者该方法函数。同时它又是在许多面试场景中经常会被面试官问到的,接下来结合例子来和大家讨论下悲观锁与乐观锁。

为什么需要锁

先讲概念太枯燥,所以我们举一个通用的生活场景作为例子。A 和 B 两个人分别去车站买从上海到北京的同一时间出发的高铁票。A 排队在 1 号售票窗,B 排队在 2 号售票窗,两人同时递出身份证买票,好巧不巧,1 和 2 号窗口的售票员同时说这班车只有一张票,怎么办?拼哪个窗口的售票员手速更快吗?于是 A 和 B 就开始吵架,可后面排队的很多人都在等。如果 A 和 B 继续吵架僵持不下,就会连带着浪费其他人的时间。经过讨论,大家一致认为,即便是要拼手速也是他俩拼。那么问题来了,用什么来拼呢?这个时候,站长出来了。他说,我这里有一把锁,会放在你们中间的位置上,谁抢到就先给谁买票,这样对 A 和 B 都公平。大家一阵欢呼,一把锁解决了抢票的纷争。这个场景放在编程语言中,就是一个典型的多线程并发场景问题。上述的 A 和 B 是两个线程,高铁票则可以看作是一个变量或者一个方法函数。如果不加锁,高铁票就会被 A 和 B 抢来抢去,变得面目全非,甚至还会出现一开始票价为 50 元,结果抢着抢着可能就被人把价格改到了 100 元。所以,给高铁票(变量或方法函数)加一个锁,谁抢到锁,就有权使用该高铁票(变量或方法函数),保证其安全。

锁的分类和应用场景
以 Java 中的锁为例,Java 中有种类丰富的锁,每种锁因其特性的不同,在不同的场景下展现出的效率也是参差不齐的。这就需要我们对锁进行合理的分类,放对位置,才能更好地使用锁。

a.线程是否给同步资源加锁?

是:悲观锁。

否:乐观锁。


b.同步资源加锁失败,线程是否需要阻塞?

是:阻塞。

否:不阻塞(自旋锁、适应性自旋锁)。


c.多个线程竞争同步资源的细节区别是?

无锁:不锁住资源,多个线程中只有一个能修改资源成功,其它线程会重试。

偏向锁:同一个线程执行同步资源时自动获取资源。

轻量级锁:多个线程竞争同步资源时,没有获取资源的线程自旋等待锁释放。

重量级锁:多个线程竞争同步资源时,没有获取资源的线程阻塞等待唤醒。


d.多个线程竞争锁时要不要排队?

排队:公平锁。

先尝试插队,插队失败再排队:非公平锁。


e.一个线程中的多个流程能不能获取同一把锁?

能:可重入锁。

不能:非可重入锁。


f.多个线程能否共享一把锁?

能:共享锁。

不能:排他锁

为了方便扣友们理解,下面将以乐观锁和悲观锁为例,简单说下锁的应用场景。

乐观锁和悲观锁

先说概念。悲观锁,从这个名字我们就能看出,这个锁的态度是比较悲观的,它会认为自己在使用变量或者方法的同时,一定会有其他的线程来跟它抢,所以,他最爱做的事情就是先加锁。等它使用完,别的线程想做啥就做,手中有锁,并发不愁。

而乐观锁呢,和悲观锁截然不同。它的态度很乐观,每次使用前,它都认为不会有别的线程跟它抢,所以每次都不会加锁,只是在更新某个数据时,才会去判断之前有没有别的线程更新这个数据。如果这个数据没有被更新,当前线程会将自己修改的数据成功写入。如果数据已经被其他线程更新,它就会根据不同的实现方式执行不同的操作(例如报错或者自动重试)。

从两者概念的不同,我们就会知道两者所适合应用的场景也是不一样的。悲观锁适合写操作多的场景,先加锁可以保证写操作时数据正确。乐观锁适合读操作多的场景,不加锁的特点能够使其读操作的性能大幅提升。光说概念有些抽象,我们来看下乐观锁和悲观锁的调用方式例子:

//--悲观锁的调用方式--//synchronizedpublic synchronized void testMethod(){    ...具体方法省略...}//ReentrantLockprivate ReentrantLock lock = new ReentrantLock();//需要保证多个线程使用的是同一个锁public void modifyPublicResources(){    lock.lock();    ...具体方法省略...    lock.unlock();}
//--乐观锁的调用方式--private AtomicInteger atomicInteger = new AtomicInteger();//需要保证多个线程使用的是同一个AtomicIntegeratomicInteger.incrementAndGet();//执行自增1
通过上面的调用方式示例,我们可以发现悲观锁基本都是先加锁之后再操作同步资源,而乐观锁就直接去操作同步资源。

那么,为什么乐观锁能够做到事先不加锁也可以正确的实现线程并发呢?这就涉及到乐观锁的主要实现方式“CAS”的技术原理了,感兴趣的扣友们可以留言,可以再开一篇来给大家聊聊。你们在工作中还遇到过哪些锁,有没有遇到过被锁耽误头秃的时候,也欢迎大家在评论区积极留言~


BY / 

本文作者:海洋

编辑&版式:Janson

声明:本文归“力扣”版权所有,如需转载请联系。


点个在看,少个 bug

微信扫码关注该文公众号作者

戳这里提交新闻线索和高质量文章给我们。
相关阅读
赠书|都2023年了,R语言可以这样学?《R语言编程—基于tidyverse》这款源自以色列的编程游戏,通过“闯关”教孩子写真实的编程语言那些意欲取代 C++ 的编程语言,成功了吗?在 C 语言中使用 getopt 解析命令行短选项 | Linux 中国时隔 20 年,这个编程语言再次“称王”!C++ 夺冠!2022 年度编程语言i-Refill | ChatGPT爆火背后,AI应用层已经到来从C和C++向Rust等内存安全编程语言的转变正在取得进展老胡阳了也不足以平民愤如果编程语言是人......C++崛起,摘得TIOBE 2022年度编程语言Epic CEO:元宇宙已达6亿用户,元宇宙编程语言Verse意义何在?国内最流行的编程语言调优,它排第一!阿根廷,今天你必需哭泣!渡十娘|关于胡鑫宇,我说几句题外话新开源!跨时代AI编程语言NGPTL++腾讯发布 2022 研发大数据报告:Go 语言蝉联最热编程语言2023需求最高的编程语言:Python、JavaScript和Java看视频涨知识|关于防疫的这些奇葩网传,你信了几个?巴金:那些年,我在谎言中过日子我们应该如何用好 AI?从 ChatGPT 到编程语言、大数据、前端Rust将迎来爆发式增长;更多国产编程语言进入视野 | 编程语言领域解读微软公布 .NET最新的编程语言支持策略T12校园评价通过编写“猜数字”游戏来学习 Ada 编程语言 | Linux 中国中文编程不如英文香?今年诞生的这些国产编程语言表示不服谷歌最好的程序员Jeff Dean:我用过 18 种编程语言硬核观察 #911 C++ 之父呼吁改变编程语言本身以提升安全性中国的新冠疫情如海啸般到来源自以色列的编程游戏,通过“闯关”教孩子写真实的编程语言What was Karl Marx's original plan for communism?黑客使用哪些编程语言?C++ 夺冠!成为 TIOBE 2022 年度编程语言硬核观察 #870 C 语言已不再仅仅是一种编程语言洋人剜眼摘心炼药?一则谣言中的大清危机
logo
联系我们隐私协议©2024 redian.news
Redian新闻
Redian.news刊载任何文章,不代表同意其说法或描述,仅为提供更多信息,也不构成任何建议。文章信息的合法性及真实性由其作者负责,与Redian.news及其运营公司无关。欢迎投稿,如发现稿件侵权,或作者不愿在本网发表文章,请版权拥有者通知本网处理。