文章目录
一、乐观锁
1、浅析乐观锁的过程
- 很多人觉得乐观锁,第一反应就是见名思意,就是以为给数据库加了一个乐观锁,但是实际上,乐观锁真正的锁一个都没加。
- 如何理解上面这句话?比如我加了一个乐观锁,我在修改的过程中,不会影响其他线程的任何操作,因为我真的没有加实际意义上的锁。(又怎么会影响其他的线程的修改呢?)
- 也就是说我在对数据库操作之前没加任何的锁,那么别的线程完全有可能在我修改的期间篡改了我要修改的数据,那么这个时候(前后数据不一致),乐观锁被激活
- 乐观锁遇到数据被篡改,乐观锁不做任何有实质性的措施,取消任何对数据库的操作,返回一个错误给用户,让用户自己解决。实际上乐观锁只是起到一个提示用户数据被修改的作用,仅此而已
- 用户的一般反应,乐观锁提示数据被修改,用户查看被修改之后数据,用户自己选择要不要重新发起相同的修改操作
2、值得思考的问题,有助于理解。
真正意义上的锁一个都没有加,乐观锁又做了什么?
乐观锁只做到了一件事,当数据被修改时抛出错误,提示用户数据已经被修改,而处理问题的方式留给用户。
乐观锁设计方式的目的是什么?
首先得说适合的场景,适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。 在多读的场景中可以提高性能,没必要加实际意义上的锁,这就是最主要的设计目的。
什么是ABA问题,如何解决ABA问题?
- ABA问题:一个数据被另一个1个线程修改2次,初始值为100,第一次修改为120,第二次修改为100,看起来数据没有被操作过,实际上,数据已经被操作过了。
- 解决方式:设置一个version字段,每修改数据一次,把version字段加一
3、其他
- 什么是乐观锁:
- 乐观锁是为了解决线程冲突情况下脏读,幻读等,乐观锁就是为了解决这个问题而产生的;乐观锁默认情况下认为数据是不会发生冲突的,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则返回给用户错误信息,让用户决定如何去做。
- 乐观锁优缺点:
- 优点
- 读写不加锁,保证了代码高速运行。悲观锁加锁解锁时上下文切换和调度延时,外加排斥等待效率非常低。
- 缺点
- ABA 问题: 如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。
- 循环判断开销大:为了保证CAS操作成功必须添加循环判断,如果长时间不成功,会给CPU带来非常大的执行开销。
- 优点
二、悲观锁
1、什么是悲观锁?常见的悲观锁。
- 悲观锁认为被它保护的数据是极其不安全的,每时每刻都有可能变动,一个事务拿到悲观锁后(可以理解为一个用户),其他任何事务都不能对该数据进行修改,只能等待锁被释放才可以执行。
- 数据库中的行锁,表锁,读锁,写锁,以及syncronized实现的锁均为悲观锁。
- 可以说会对数据库加以限制,会对其他线程产生影响的锁,都可以称为悲观锁
- 悲观锁基本就是大家最为普通的理解方式,给数据加上锁,使事务执行的过程中不被其他事务所干扰
2、设计目的,适合场景
- 适合场景:适合多写的场景,利用数据库中的锁机制来实现数据变化的顺序执行,这是最有效的办法
- 设计目的:使业务的执行有合适的执行顺序,解决并行冲突的问题
3、其他
- 什么是数据库的表锁和行锁:我们经常使用的数据库是mysql,mysql中最常用的引擎是Innodb,Innodb默认使用的是行锁。而行锁是基于索引的,因此要想加上行锁,在加锁时必须命中索引,否则将使用表锁。
- 优点:悲观锁利用数据库中的锁机制来实现数据变化的顺序执行,这是最有效的办法
- 缺点:一个事务用悲观锁对数据加锁之后,其他事务将不能对加锁的数据进行除了查询以外的所有操作,如果该事务执行时间很长,那么其他事务将一直等待,那势必影响我们系统的吞吐量。