乐观锁

乐观锁与悲观锁

十年热恋 提交于 2020-03-14 04:40:25
何谓悲观锁与乐观锁 乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。 (1)悲观锁: 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程)。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。Java中 synchronized 和 ReentrantLock 等独占锁就是悲观锁思想的实现。 (2)乐观锁: 总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中 java.util.concurrent.atomic 包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。 两种锁的使用场景 从上面对两种锁的介绍,我们知道两种锁各有优缺点,不可认为一种好于另一种,像乐观锁适用于写比较少的情况下(多读场景)

乐观锁与悲观锁

一笑奈何 提交于 2020-03-11 08:25:14
锁 (Lock) 锁是一种保证数据安全的机制和手段,其并不是特定于某项技术的,其主要是通过在并发下控制多个操作的顺序执行,以此来保证数据安全地变动 例如在程序中,当多个线程修改共享变量时,可以给修改操作上锁 (syncronized) ;在数据库中,当多个用户修改表中同一数据时,我们可以给该行数据上锁 悲观锁 (Pessimistic Concurrency Control) 总是假设最坏的情况,每次取数据的时候都认为别人会修改,所以每次取数据都会加锁。这样别人在操作这条数据的时候,如果没有拿到锁,就会发生阻塞,操作就无法执行。 数据库中的行锁,表锁,读锁,写锁等都是悲观锁 乐观锁 (Optimistic Concurrency Control) 总是假设最好的情况,每次取数据的时候都认为别人不会修改数据,所以不对数据加锁。但是会在更新的时候判断一下在此期间别人有没有更新这个数据,判断可以使用版本号机制和 CAS 算法实现。 乐观锁通常是通过在表中增加一个版本 (version) 或时间戳 (timestamp) 来实现,其中版本最为常用. 事务从数据库中取数据时,会将该数据的版本也取出来 (v1) ,当事务对数据变动完毕需要提交至数据库时,会将之前取出的 v1 与数据的最新版本 v2 进行对比 v1 = v2 :说明数据变动期间没有其他事务对该数据进行修改

悲观锁与乐观锁

这一生的挚爱 提交于 2020-03-11 07:33:51
1、悲观锁并发控制方案,就是在各种情况下都上锁,上锁之后,就只有一个线程可以操作这些内容了。在不同的情况下可以设置不同的锁,比如:行级锁,表级锁。 2、乐观锁并发控制方案,是不加锁的,写入的时候会判断当前数据的版本号跟es中的版本号是否相同,如果相同就直接写入;如果版本号不相同,说明数据已经被其他线程修改过了,此时该线程会从es中重新读取最新版本的数据,再次执行逻辑处理,然后重复以上流程。 ----------------------------------------------------------------------------------------------------------- 悲观锁与乐观锁的优缺点: 1、悲观锁的优点:方便,直接加锁,对应用程序来说,透明,不需要做额外的操作。 缺点:并发能力很低,同一时间,只能有一条线程操作数据。 2、乐观锁的优点:并发能力很高,不给数据加锁,可以大量线程并发操作。 缺点:麻烦,每次更新数据的时候,都要先对比版本号,然后可能需要重新加载数据,再次执行逻辑处理,再写;这个过程可能要重复很多次。 来源: https://www.cnblogs.com/qinjf/p/8460186.html

乐观锁与悲观锁、自旋锁

做~自己de王妃 提交于 2020-03-11 03:33:08
乐观锁 乐观锁是一种乐观的思想,即认为读多写少,遇到并发的可能性低, 每次拿数据时都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据 ,可以使用版本号机制和 CAS 算法实现。 Java 中的乐观锁基本都是通过 CAS 操作实现的, CAS 是一种更新的原子操作,比较当前值跟传入值是否一样,一样则更新,否则失败。 悲观锁 悲观锁就是悲观的思想,即认为写多,遇到并发的可能性高,每次拿数据时,都会认为别人会修改数据,所以在每次读数据的时候都会上锁,这样当别人想读写这个数据时就会阻塞,直到拿到锁。 (共享资源每次只给一个线程使用,其它线程阻塞,用完后再把资源转让给其它线程) 。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。 Java 中的悲观锁就是 Synchronized,AQS 框架下的锁则是先尝试 CAS 乐观锁去获取锁,获取不到,才会转换为悲观锁,如 ReentrantLock。 乐观锁的缺点 ABA 问题 CAS 会导致 “ABA 问题”。CAS 算法实现的一个重要前提是需要取出内存中某时刻的数据,而在下一时刻比较并替换,那么在这个时间差会导致数据的变化。 比如说一个线程 one 从内存位置 V 中取出 A,这时候另一个线程 two 也从内存中取出 A,并且 two

字节跳动面试,问了我乐观锁和悲观锁的AQS、sync和Lock,这个回答让我拿了offer

爷,独闯天下 提交于 2020-03-06 11:35:00
前言 关于线程安全一提到可能就是加锁,在面试中也是面试官百问不厌的考察点,往往能看出面试者的基本功和是否对线程安全有自己的思考。 那锁本身是怎么去实现的呢?又有哪些加锁的方式呢? 我今天就简单聊一下乐观锁和悲观锁,他们对应的实现 CAS ,Synchronized,ReentrantLock 正文 一个120斤一身黑的小伙子走了进来,看到他微微发福的面容,看来是最近疫情伙食好运动少的结果,他难道就是今天的面试官渣渣丙? 等等难道是他?前几天刷B站看到的不会是他吧!!! 是的我已经开始把面试系列做成视频了,以后会有各种级别的面试,从大学生到阿里P7+的面试,还有阿里,拼多多,美团,字节风格的面试我也都约好人了,就差时间了,大家可以去B站搜: 三太子敖丙 观看 我也不多跟你BB了,我们直接开始好不好,你能跟我聊一下CAS么? CAS(Compare And Swap 比较并且替换)是乐观锁的一种实现方式,是一种轻量级锁,JUC 中很多工具类的实现就是基于 CAS 的。 CAS 是怎么实现线程安全的? 线程在读取数据时不进行加锁,在准备写回数据时,先去查询原值,操作的时候比较原值是否修改,若未被其他线程修改则写回,若已被修改,则重新执行读取流程。 举个栗子:现在一个线程要修改数据库的name,修改前我会先去数据库查name的值,发现name=“ 帅丙 ”,拿到值了,我们准备修改成name

悲观所与乐观锁

半腔热情 提交于 2020-03-03 00:13:09
一、乐观锁 总是认为不会产生并发问题,每次去取数据的时候总认为不会有其他线程对数据进行修改,因此不会上锁,但是在更新时会判断其他线程在这之前有没有对数据进行修改,一般会使用版本号机制或CAS操作实现。 version方式: 一般是在数据表中加上一个数据版本号version字段,表示数据被修改的次数,当数据被修改时,version值会加一。当线程A要更新数据值时,在读取数据的同时也会读取version值,在提交更新时,若刚才读取到的version值为当前数据库中的version值相等时才更新,否则重试更新操作,直到更新成功。 核心SQL代码: update table set x=x+1, version=version+1 where id=#{id} and version=#{version}; CAS操作方式: 即compare and swap 或者 compare and set,涉及到三个操作数,数据所在的内存值,预期值,新值。当需要更新时,判断当前内存值与之前取到的值是否相等,若相等,则用新值更新,若失败则重试,一般情况下是一个自旋操作,即不断的重试。 一、悲观锁 总是假设最坏的情况,每次取数据时都认为其他线程会修改,所以都会加锁(读锁、写锁、行锁等),当其他线程想要访问数据时,都需要阻塞挂起。可以依靠数据库实现,如行锁、读锁和写锁等,都是在操作之前加锁,在Java中

Padded优化LinkedTransferQue并发性能是错误方向

孤街醉人 提交于 2020-03-01 08:44:15
在Grizzly中,自带了LinkedTransferQueue,和JDK 7自带的LinkedTransferQueue有所不同,不同之处就是使用PaddedAtomicReference来提升并发性能,其实这是一种错误的编码技巧,没有意义! AtomicReference和LinkedTransferQueue的本质是乐观锁,乐观锁的在激烈竞争的时候性能都很糟糕,乐观锁应使用在非激烈竞争的场景,为乐观锁优化激烈竞争下的性能,是错误的方向,因为如果需要激烈竞争,就应该使用悲观锁。 以下是一个JDK中内置乐观锁悲观锁的对照表: 乐观锁 -----> 悲观锁 AtomicInteger -----> Lock + volatile int AtomicLong -----> Lock + volatile long AtomicReference -----> Lock + volatile LinkedTransferQueue -----> LinkedBlockingQueue 在激烈竞争中,LinkedTransferQueue的性能,远远低于LinkedBlockingQueue,使用PaddedAtomicReference优化也是一样的。如果不激烈竞争,Padded-LinkedTransferQueue和LinkedTransferQueue相比也没有什么优势。

Hibernate_Optimistic Lock_乐观锁

て烟熏妆下的殇ゞ 提交于 2020-02-29 21:51:52
Hibernate_Optimistic Lock_乐观锁 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。 悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。乐观锁机制在一定程度上解决了这个问题。乐观锁,大多是基于数据版本(Version)记录机制实现。 何谓数据版本?即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个"version"字段来实现。 乐观锁的工作原理:读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。 Optimistic locking properties (optional) When using long transactions or conversations that span several database transactions, it is useful to store versioning data to ensure that if the same entity is updated by two conversations, the

hibernate 锁机制

我是研究僧i 提交于 2020-02-29 02:58:00
Hibernate 悲观锁,乐观锁 1.悲观锁 它指的是对数据被外界修改持保守态度。假定任何时刻存取数据时,都可能有另一个客户也正在存取同一笔数据,为了保持数据被操作的一致性,于是对数据采取了数据库层次的锁定状态,依靠数据库提供的锁机制来实现。 基于jdbc实现的数据库加锁如下: select * from account where name="Erica" for update 在更新的过程中,数据库处于加锁状态,任何其他的针对本条数据的操作都将被延迟。本次事务提交后解锁。 而hibernate悲观锁的具体实现如下: String sql="查询语句"; Query query=session.createQuery(sql); query.setLockMode("对象",LockModel.UPGRADE); 说到这里,就提到了hibernate的加锁模式: LockMode.NONE:无锁机制。 LockMode.WRITE:Hibernate在Insert和Update记录的时候会自动获取。 LockMode.READ:Hibernate在读取记录的时候会自动获取。 这三种加锁模式是供hibernate内部使用的,与数据库加锁无关: LockMode.UPGRADE:利用数据库的for update字句加锁。 在这里我们要注意的是:只有在查询开始之前

java学习记录---CAS乐观锁

最后都变了- 提交于 2020-02-27 22:48:52
CAS,全称 Compare And Swap (比较与交换),是一种乐观锁,同样是锁相比 synchronized 性能却要高不少,因为是 synchronized 阻塞的,而CAS是非阻塞的。CAS主要有3个操作数,内存值V,预期的旧值A,需要修改的新值B,可以这样理解:在V的地址把A改成B,当V位置的值与预期的旧值A相同时候,则修改成B,否则不更新。 下面看个图简单理解一下CAS:当线程1和线程2同时操作内存V,线程1想要把内存V的变量值从A(2)改成B(1)而线程2想要把V的变量值从A(2)改成B(3)。假设这个时候是线程1优先抢到资源所以线程1先进行CAS操作,这个时候预期旧值2是相等的则执行了更新,更新完后内存V的变量值就变成1,这个时候线程2才进入比较预期的A值与V中实际的变量值已经不相同了,所以更新失败。 这个图看上去是 Compare And Swap 是同时操作,但实际上是分2部执行:1.比较(compare),2.交换(swap),它的原子性是通过硬件实现的,而不是我们java代码实现 java提供的CAS操作类 我们随便找其中一个Atomic类学习 当V的值与A相等则更新成功 public static void main(String[] args) { // 定义 Integer 的 CAS 类 AtomicInteger AI = new