乐观锁和悲观锁_什么是悲观锁和乐观锁?

b384104b12ccc78be0c67480593003dc.png

思维导图

a365024e589c2752f36067a8fc56c687.png
文章已收录Github精选,欢迎Star:https://github.com/yehongzhi/learningSummary

悲观锁

悲观锁是平时开发中经常用到的一种锁,比如ReentrantLocksynchronized等就是这种思想的体现,它总是假设别的线程在拿线程的时候都会修改数据,所以每次拿到数据的时候都会上锁,这样别的线程想拿这个数据就会被阻塞。如图所示:

eee323890517d1977c75c999c9c4589c.png

synchronized是悲观锁的一种实现,一般我们都会有这样使用:

private static Object monitor = new Object();public static void main(String[] args) throws Exception {//锁一段代码块synchronized (monitor){}
}
//锁实例方法,锁对象是this,即该类实例本身
public synchronized void doSome(){}
//锁静态方法,锁对象是该类,即XXX.class
public synchronized static void add(){}

我们以最简单的同步代码块来分析,其实就是将synchronized作用于一个给定的实例对象monitor,即当前实例对象就是锁对象,每次当线程进入synchronized包裹的代码块时就会要求当前线程持有monitor实例对象锁,如果当前有其他线程正持有该对象锁,那么新到的线程就必须等待,这样也就保证了每次只有一个线程执行synchronized内包裹的代码块

从上面的分析中可以看出,悲观锁是独占和排他的,只要操作资源都会对资源进行加锁。假设读多写少的情况下,使用悲观锁的效果就不是很好。这时就引出了接下来要讲的乐观锁。

乐观锁

乐观锁,顾名思义它总是假设最好的情况,线程每次去拿数据时都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,如果这个数据没有被更新,当前线程将自己修改的数据成功写入。如果数据已经被其他线程更新,则根据不同的实现方式执行不同的操作(例如报错或者自动重试)。如图所示:

6d29dd17d5812b1592419d2d0cf9e185.png

一般乐观锁在java中是通过无锁编程实现的,最常见的就是CAS算法,比如Java并发包中的原子类的递增操作就是通过CAS算法实现的。

CAS算法,其实就是Compare And Swap(比较与交换)的意思。目的就是将内存的值更新为需要的值,但是有个条件,内存值必须与期待的原内存值相同。展开来说,我们有三个变量,内存值M,期望的内存值E,更新值U,只有当M==E时,才会将M更新为U

CAS算法实现的乐观锁在很多地方有应用,比如并发包的原子类AtomicInteger类。在自增的时候就使用到CAS算法。

public final int getAndIncrement() {return unsafe.getAndAddInt(this, valueOffset, 1);
}//var1 是this指针
//var2 是偏移量
//var4 是自增量
public final int getAndAddInt(Object var1, long var2, int var4) {int var5;do {//获取内存,称之为期待的内存值Evar5 = this.getIntVolatile(var1, var2);//var5 + var4的结果是更新值U//这里使用JNI方法,每个线程将自己内存中的内存值M与var5期望值比较,//如果相同则更新为var5 + var4,返回true跳出循环。//如果不相同,则把内存值M更新为最新的内存值,然后自旋,直到更新成功为止} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));//返回更新后的值return var5;
}public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);

所以可以看出CAS算法其实是无锁的。好处是在读多写少的情况下,性能是比较好的。那么CAS算法的缺点其实也是很明显的。

  • ABA问题。线程C将内存值A改成了B后,又改成了A,而线程D会认为内存值A没有改变过,这个问题就称为ABA问题。解决办法很简单,在变量前面加上版本号,每次变量更新的时候变量的版本号都+1,即A->B->A就变成了1A->2B->3A
  • 在写多读少的情况下,也就是频繁更新数据,那么会导致其他线程经常更新失败,那么就会进入自旋,自旋时会占用CPU资源。如果资源竞争激烈,多线程自旋的时间长,导致消耗资源

使用场景

读多写少的场景下,更新时很少发生冲突,使用乐观锁,减少了上锁和释放锁的开销,可以有效地提升系统的性能。

相反,在写多读少的场景下,如果使用乐观锁会导致更新时经常产生冲突,然后线程会循环重试,这样会增大CPU的消耗。在这种情况下,建议可以使用悲观锁

总结

在日常的开发中,悲观锁和乐观锁应该是见得最多,用得最多的锁,比如最常见的synchronizedReentrantLock是悲观锁,并发包中的原子类和ConcurrentHashMap则用了乐观锁。锁的实现并不复杂,关键是搞懂这两种锁的思想,这样才能在合适的地方使用合适的锁。

这篇文章就讲到这里了,希望看完后能有所收获,感谢你的阅读。

觉得有用就点个赞吧,你的点赞是我创作的最大动力~

我是一个努力让大家记住的程序员。我们下期再见!!!

能力有限,如果有什么错误或者不当之处,请大家批评指正,一起学习交流!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/488938.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为了研究因果关系,原来科学家在这么多方向上都有尝试

来源:混沌巡洋舰1. 为何关注因果关系在现代科学之前,不管东西方,都是从经验出发,通过归纳获得知识,然而这样的知识,受限于观测,无法产生突破性的成果,在这样的模式下,再探…

mysql 有一组经纬度 返回在某个区域内_Qt编写地图综合应用17-地址经纬度互转

## 一、前言地址和经纬度互相转换的功能也经常用到,比如上次的路线方案查询的功能,之前官网是提供了直接输入出发地点和目的地的中文汉字,就可以查询到最优的路线,后面只支持输入出发地点和目的地的经纬度坐标了,这个就…

杨强 : 迁移学习——人工智能的最后一公里

来源:智能系统学报11月30日上午,第九届吴文俊人工智能科学技术奖颁奖典礼暨2019中国人工智能产业年会在苏州广电大厦演播厅隆重举行。本届大会主题是“突破关键技术赋能产业落地”。大会邀请到国家部委专家、两院院士和产业领军人士,围绕77场…

直接点oracle表编辑器,DbForge Studio for Oracle入门教程:如何在表编辑器中创建表...

dbForge Studio for Oracle是一个功能强大的集成开发环境(IDE),它提供了通用的数据编辑工具来管理数据库内和外部数据,能够帮助Oracle开发者提高PL/SQL的编码速度。【dbForge Studio for Oracle 最新试用版下载】在本文示例中,我们将创建一个…

设置窗口置顶_这三个应用,每一个都能让你置顶。

| 当你有多个窗口同时打开,置顶其中某个或某些,能够方便你对比、学习、抄写……但不是所有软件都有这个功能,所以你需要今天的小干货。|-----------你的高效生活视频书。将窗口置顶,可以方便我们对比、写作、修改文案或代码&#…

汽车传感器科普

来源:湖杉资本先进驾驶辅助系统(Advanced Driver Assistant System),简称ADAS,是利用安装于车上的各式各样的传感器, 在第一时间收集车内外的环境数据, 进行静、动态物体的辨识、侦测与追踪等技…

人工智能的现状与未来

来源: CIO之家几十年来计算速度飞速提高,从最初的科学数学计算演变到了现代的各种计算机应用领域,诸如多媒体应用,计算机辅助设计,数据库,数据通信,自动控制等等,人工智能是计算机科…

php分页技术的作用,分页原理技术细节剖析(php+mysql)实例

提到分页,大家都不陌生,在我们日常浏览网页时常遇到,尤其新闻文章列表等都有分页,如下图所示:分页实例下面,通过一个实例为大家剖析一下分页原理上技术细节。一、功能开发思路在分页功能的实现前&#xff0…

2020年物联网发展现状与趋势预测

来源:北京物联网智能技术应用协会一、综述物联网源于互联网领域,是信息科学技术产业的第三次革命。物联网是基于互联网,让所有物体能够独立寻址的普通物理对象实现互联互通的网络。简单说,就是通过安装信息传感设备,如…

shell中执行某条语句失败能不能重复执行_如何理解Mysql中的事务隔离级别?

要说清楚Mysql中的事务隔离级别,我们先从事务的定义说起。事务,是一个或一组sql语句组成的一个执行单元,这个执行单元要么全部执行,要么全部不执行。整个单独单元作为一个不可分割的整体,如果单元中某条sql语句一旦执行…

oracle 试图访问已经在使用的事物处理临时表,解决ORA-14450:试图访问已经在使用的事务处理临时表...

在开发使用过程中,一个存储过程用到表TMP_DA_GMS,允许程序的时候报错,后台查询到错误原因是因为表里有个字段需要设置为可以为N在开发使用过程中,一个存储过程用到表TMP_DA_GMS,允许程序的时候报错,后台查询到错误原因是因为表里有…

《数字孪生体技术白皮书(2019)》(简版)全文

来源:《数字孪生体实验室原创》12月27日,数字孪生体实验室与安世亚太联合正式发布了《数字孪生体技术白皮书(2019)》。白皮书的第一部分关注对数字孪生体的抽象和总结。无论是参考架构、成熟度模型还是关键技术,都以“…

sql 删除字段中下划线_SQL基础教程知识点总结

1. ●列 ●字段 ●行 ●记录 2. SQL 语句及其种类 DDL DDL(Data Definition Language,数据定义语言)用来创建或者删除存储 数据用的数据库以及数据库中的表等对象。DDL 包含以下几种指令。 CREATE:创建数据库和表等对象 DROP: 删除数据库和表等对象 ALTER: 修改数据…

王恩东院士:AI计算是未来的核心生产力

来源:蓝海长青智库12月27日,以“超算无界、智创未来”为主题的2019国际超级计算产业博览会在济南召开。中国工程院院士、浪潮集团首席科学家王恩东在大会发表《智慧计算 未来动力》主题演讲。王恩东指出,人工智能正在驱动前所未有的社会变革&…

​采访了14位技术公司的创始人,他们如何看待2020年的AI行业?

来源:KDnuggets编译:木槿、张大笔茹、楚阳科幻元年2020年马上就要来了。对于技术行业来说,这一年会有哪些值得期待的变化?KDnuggets采访了14位科技前沿的技术公司创始人,并汇总了他们眼中的2020年:关于人工…

前端编程基础

网页前端编程基础 HTML 是用来描述网页的一种语言。HTML 指的是超文本标记语言 (Hyper Text Markup Language)HTML 不是一种编程语言&#xff0c;而是一种标记语言 (markup language)标记语言是一套标记标签 (markup tag)HTML 使用标记标签来描述网页<html> <body>…

spark sql合并小文件_Spark SQL小文件问题在OPPO的解决方案

Spark SQL小文件是指文件大小显著小于hdfs block块大小的的文件。过于繁多的小文件会给HDFS带来很严重的性能瓶颈&#xff0c;对任务的稳定和集群的维护会带来极大的挑战。一般来说&#xff0c;通过Hive调度的MR任务都可以简单设置如下几个小文件合并的参数来解决任务产生的小文…

白春礼:探究物质世界奥秘的一把金钥匙——纪念元素周期表发表150周年

来源&#xff1a;中国科学报联合国大会宣布2019年为国际化学元素周期表年&#xff0c;旨在纪念俄罗斯化学家门捷列夫在150年前发表元素周期表这一科学发展史上的重大成就。世界万物是由什么最基本的物质构成的&#xff1f;这些最基本的物质又是怎样变成万物世界的&#xff1f;这…

莫名的证书错误...ERROR ITMS-90035:Invalid Signature.

请删除 .DS_Store 这种类似的文件再尝试转载于:https://www.cnblogs.com/decode1234/p/6529601.html

linux里工作目录的字体变蓝,netterm访问Linux时字体和背景颜色随目录发生改变的问题解决...

方法很多&#xff0c;除了改用其他仿真终端程序外&#xff0c;继续使用netterm可用下面方法解决。方法1&#xff1a;修改netterm参数&#xff0c;最简单选项-->屏幕颜色-->允许图形编译码 重置颜色至默认值点选上&#xff0c;见下图&#xff1a;这种方法的最大特点是目录…