JAVA并发编程之乐观锁、悲观锁实现讲解

悲观锁


认为随时有可能发生冲突,用锁保护所有临界区。日常使用的锁绝大多数都是悲观锁。

优点:

1. 确保安全性,悲观锁临界区内不会发生并发问题。

2. 简单方便。

3. 使用悲观锁,在临界区内操作数据成功率高。

缺点:

1. 如果临界区内耗时长,会影响程序整体工作效率。

2. 可能产生死锁。

乐观锁


乐观的认为不会发生并发冲突,不为临界区代码加锁,但会持有在运行临界区前的版本号。在完成临界区后对比版本号,如果版本号没被更新说明没有产生冲突,进行数据更新并更新版本号。如果发现版本号被其他线程更新,则回滚所有操作并重试。乐观锁不是锁,是一种概念。

优点:

1. 不会产生死锁问题。

2. 在并行冲突情况低的多读程序中,工作效率比悲观锁高。

3. 允许多个线程进入临界区,在不同时对某些数据修改的情况下,效率很高。

缺点:

1. 对于回滚代价大的程序,不易使用乐观锁。

2. 冲突情况多时,效率不一定比悲观锁高。

3. 乐观锁实现复杂。

JAVA中乐观锁与悲观锁


java中较为常用的锁是synchronized和ReentrantLock,实际上这两种锁都是悲观锁,悲观锁就是一般的锁,java并不强调悲观和乐观的概念。在java并发里悲观和乐观的区分不如说是上锁和Ad-hoc线程封闭的区别。通俗的理解,悲观就是用锁控制多线程访问,乐观更多的是用程序本身的规则约束数据不能被错误的访问到。

如何在java中实现乐观锁?回到乐观锁的概念,用版本来控制数据不被错误的访问。在你的java程序中添加int活着double型的version字段,但是你要确保版本的访问和最后数据的修改锁是被锁保护的,这样做大概采用了乐观锁的概念,能够起到的效果是减少了临界区的范围,如果你的事务很长,采用这种方法尚可。不要在不能使用乐观锁的地方强行使用乐观锁,它的概念不是为java而生的而是数据库。不要弄巧成拙。

数据库中乐观锁与悲观锁


悲观锁实现

在对任意记录进行修改前,先尝试为该记录加上排他锁(exclusive locking)。

如果加锁失败,说明该记录正在被修改,那么当前查询可能要等待或者抛出异常。

如果成功加锁,那么就可以对记录做修改,事务完成后就会解锁了。

其间如果有其他对该记录做修改或加排他锁的操作,都会等待我们解锁或直接抛出异常。

悲观锁是一种默认产生冲突的处理概念,上述四个步骤表达了悲观锁的含义。

?
1
2
3
4
start transaction ;
select A from B where C for update ;
update B set D;
commit ;

第一步开始事务,第二步select末尾for update表示在此次事务提交完成之前select查询到的语句被锁定,在事务结束之前不会被改变。

乐观锁实现

在大项目中,数据库的每一张表至少有10多个字段。即使是很简单的一张表也会有很多字段,这是因为每一张表都有相同的一些记录性字段,比如:最后修改时间、最后修改人、版本号…我们可以利用其中的版本号来实现乐观锁。

?
1
2
3
4
select A,version from B where C
...(其他操作)
update B set D,version=version+1
where C and version = E;(E是已知最近版本号)

单单是数据库不便于操作,可以结合代码记录版本号,事务完成后进行验证。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值