首页 > 其他分享 >关于乐观锁、悲观锁、可重入锁....

关于乐观锁、悲观锁、可重入锁....

时间:2023-04-25 21:01:07浏览次数:36  
标签:重入 排队 ReentrantLock .... 乐观 获取 线程 悲观


并发编程----乐观锁、悲观锁、可重入锁…..

作为一个Java开发多年的人来说,肯定多多少少熟悉一些锁,或者听过一些锁。今天就来做一个锁相关总结。

关于乐观锁、悲观锁、可重入锁...._多线程

需要高清图,进入公众号联系我

悲观锁和乐观锁

悲观锁

顾名思义,他就是很悲观,把事情都想的最坏,是指该锁只能被一个线程锁持有,如果A线程获取到锁了,这时候线程B想获取锁只能排队等待线程A释放。

在数据库中这样操作:

select user_name,user_pwd from t_user for update;
乐观锁

顾名思义,乐观,人乐观就是什么事都想得开,闯到桥头自然直。乐观锁就是我都觉得他们都没有拿到锁,只有我拿到锁了,最后再去问问这个锁真的是我获取的吗?是就把事情给干了。

典型的代表:CAS=Compare and Swap 先比较哈,资源是不是我之前看到的那个,是那我就把他换成我的。不是就算了。

在Java中java.util.concurrent.atomic包下面的原子变量就是使用了乐观锁的一种实现方式CAS实现。

通常都是 使用version、时间戳等来比较是否已被其他线程修改过。

update t_user set name="Java后端技术全栈" where t_version=1
使用悲观锁还是使用乐观锁?

在乐观锁与悲观锁的选择上面,主要看下两者的区别以及适用场景就可以了。

响应效率

如果需要非常高的响应速度,建议采用乐观锁方案,成功就执行,不成功就失败,不需要等待其他并发去释放锁。乐观锁并未真正加锁,效率高。一旦锁的粒度掌握不好,更新失败的概率就会比较高,容易发生业务失败。

冲突频率

如果冲突频率非常高,建议采用悲观锁,保证成功率。冲突频率大,选择乐观锁会需要多次重试才能成功,代价比较大。
重试代价

如果重试代价大,建议采用悲观锁。悲观锁依赖数据库锁,效率低。更新失败的概率比较低。

乐观锁如果有人在你之前更新了,你的更新应当是被拒绝的,可以让用户从新操作。悲观锁则会等待前一个更新完成。这也是区别。

公平锁和非公平锁

公平锁

顾名思义,是公平的,先来先得,FIFO;必须遵守排队规则。不能僭越。多个线程按照申请锁的顺序去获得锁,线程会直接进入队列去排队,永远都是队列的第一位才能得到锁。

关于乐观锁、悲观锁、可重入锁...._编程语言_02


ReentrantLock中默认使用的非公平锁,但是可以在构建ReentrantLock实例时候指定为公平锁。

ReentrantLock fairSyncLock = new ReentrantLock(true);

假设线程 A 已经持有了锁,这时候线程 B 请求该锁将会被挂起,当线程 A 释放锁后,假如当前有线程 C 也需要获取该锁,那么在公平锁模式下,获取锁和释放锁的步骤为:

  1. 线程A获取锁--->线程A释放锁
  2. 线程B获取锁--->线程B释放锁;
  3. 线程C获取锁--->线程释放锁;

优点

所有的线程都能得到资源,不会饿死在队列中。

缺点

吞吐量会下降很多,队列里面除了第一个线程,其他的线程都会阻塞,CPU唤醒阻塞线程的开销会很大。

非公平锁

顾名思义,老子才不管你们谁先排队的,也就是平时大家在生活中很讨厌的。生活中排队的很多,上车排队、坐电梯排队、超市结账付款排队等等。但是不是每个人都会遵守规则站着排队,这就对站着排队的人来说就不公平了。等抢不到后再去乖乖排队。

多个线程去获取锁的时候,会直接去尝试获取,获取不到,再去进入等待队列,如果能获取到,就直接获取到锁。

关于乐观锁、悲观锁、可重入锁...._并发编程_03


上面说过在ReentrantLock中默认使用的非公平锁,两种方式

ReentrantLock fairSyncLock = new ReentrantLock(false);

或者

ReentrantLock fairSyncLock = new ReentrantLock();

都可以实现非公平锁。

优点

可以减少CPU唤醒线程的开销,整体的吞吐效率会高点,CPU也不必去唤醒所有线程,会减少唤起线程的数量。

缺点

大家可能也发现了,这样可能导致队列中间的线程一直获取不到锁或者长时间获取不到锁,导致饿死。

独享锁和共享锁

独享锁

独享锁也叫排他锁/互斥锁,是指该锁一次只能被一个线程锁持有。如果线程T对数据A加上排他锁后,则其他线程不能再对A加任何类型的锁。获得排他锁的线程既能读数据又能修改数据。JDK中的synchronized和JUC中Lock的实现类就是互斥锁。

共享锁

共享锁是指该锁可被多个线程所持有。如果线程T对数据A加上共享锁后,则其他线程只能对A再加共享锁,不能加排他锁。获得共享锁的线程只能读数据,不能修改数据。

对于ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁。

  1. 读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。
  2. 独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。

可重入锁

若当前线程执行中已经获取了锁,如果再次获取该锁时,就会获取不到被阻塞。

public class RentrantLockDemo {
    public synchronized void test(){
        System.out.println("test");
    }

    public synchronized void test1(){
        System.out.println("test1");
        test();
    }

    public static void main(String[] args) {
        RentrantLockDemo rentrantLockDemo = new RentrantLockDemo();
        //线程1
        new Thread(() -> rentrantLockDemo.test1()).start();
    }
}

当一个线程执行test1()方法的时候,需要获取rentrantLockDemo的对象锁,在test1方法汇总又会调用test方法,但是test()的调用是需要获取对象锁的。

可重入锁也叫递归锁,指的是同一线程外层函数获得锁之后,内层递归函数仍然有获取该锁的代码,但不受影响。

关于锁是如何实现可重入的,请参考前面的文章。

标签:重入,排队,ReentrantLock,....,乐观,获取,线程,悲观
From: https://blog.51cto.com/u_11702014/6225180

相关文章

  • 毕业5年的同学突然告诉我,他已经是年薪30W的自动化测试工程师....
    作为一名程序员,都会对自己未来的职业发展而焦虑。一方面是因为IT作为知识密集型的行业,知识体系复杂且知识更新速度非常快,“一日不学就会落后”。​另外一方面,IT又是劳动密集型的行业,不仅业人员多,而且个人在平时的开发过程中有大量的重复劳动(如CRUD),自己的能力没有随年龄的增加而......
  • 面试必备之乐观锁与悲观锁 一般有用 看1
    何谓悲观锁与乐观锁乐观锁对应于生活中乐观的人总是想着事情往好的方向发展,悲观锁对应于生活中悲观的人总是想着事情往坏的方向发展。这两种人各有优缺点,不能不以场景而定说一种人好于另外一种人。悲观锁总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿......
  • 从业4年的软件测试工程师,你只会点点点?我劝您转行吧.....
    我越来越担心我作为一个测试工程师的未来。恍然间,发现自己在这个行业里已经摸爬滚打了五年了,原以为自己就凭已有的项目经验和工作经历怎么着也应该算得上是一个业内比较资历的人士了,但是今年在换工作的过程中却遭到了重大的挫折。详细过程我就不再叙述,在此,只想给大家说一说被拒绝......
  • Android问题解决:android.os.FileUriExposedException: file:///storage/......Intent.
    文章目录一、遇到问题二、解决问题三、分析问题一、遇到问题---------beginningofcrash2022-12-2720:18:15.01014422-14422/com.lisi.evidence_boxE/AndroidRuntime:FATALEXCEPTION:mainProcess:com.lisi.evidence_box,PID:14422android.os.FileUriExpose......
  • hibernate 乐观锁与悲观锁使用
    评:Hibernate支持两种锁机制:即通常所说的“悲观锁(PessimisticLocking)”和“乐观锁(OptimisticLocking)”。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。......
  • 乐观锁和悲观锁
    什么是悲观锁?悲观锁总是假设最坏的情况,认为共享资源每次被访问的时候就会出现问题(比如共享数据被修改),所以每次在获取资源操作的时候都会上锁,这样其他线程想拿到这个资源就会阻塞直到锁被上一个持有者释放。像Java中synchronized和ReentrantLock等独占锁就是悲观锁思......
  • python-悲观锁和乐观锁
    乐观锁和悲观锁它们都是一种思想,都是人们定义出来的概念,和语言无关并发控制:当程序出现并发的问题时,我们需要保证在并发情况下数据的准确性,以保证当前用户在和其他用户一起操作时,得到的结果和他单独操作时得到的结果是一样的,没有做好并发控制,就可能导致脏读、幻读、不可重复读等问......
  • 乐观锁,悲观锁
    悲观锁乐观锁的实现fromdjango.shortcutsimportrender,HttpResponse#Createyourviewshere.from.modelsimportBook,Orderfromdjango.dbimporttransaction###回滚点的使用#defseckill(request):#withtransaction.atomic():##设置回滚......
  • 19c环境,运行DBCA创建CDB时,报错ORA-01519: error while processing file:?/rdbms/admin
    1、同事新搭建的一套19CRAC,补丁为19.10,运行DBCA安装CDB数据库时报错,错误日志如下所示:ORA-01519:errorwhileprocessingfile:?/rdbms/admin/dcore.bsq.....ORA-00604:erroroccurredatrecursiveSQLlevel1ORA-01119:errorincreatingdatabasefile'+DATA01/CDB1/pdb......
  • [Maven] The JAVA_HOME environment variable is not definded...... 配置错误日志
    ...因为是第一次配置Maven,所以出现了很多错误所以列举一二。出现找不到Java_Home环境变量的时候,如图。这个时候可能是,你的Java_Home路径配置错误,在Java_Home路径中,将\bin删掉,在path后面跟\bin,如%java_home%\bin,而不是直接在java_home中直接写死。......