设为首页 加入收藏

TOP

Java并发编程-各种锁(七)
2018-03-18 16:21:30 】 浏览:810
Tags:Java 并发 编程 各种
entrantReadWriteLock为两个锁提供了可重入的加锁语义,它是继承了ReadWriteLock,扩展了ReadWriteLock。它与ReadWriteLock相同,ReentrantReadWriteLock能够被构造


为非公平锁(构造方法不设置参数,默认是非公平),或者公平。在公平锁中,选择权交给等待时间最长的线程;如果锁由读者获得,而一个线程请求写入锁,那么不再允许读者获得读取锁,直到写者被受理,平且已经释放了写锁。


在非公平的锁中,线程允许访问的顺序是不定的。由写者降级为读者是允许的;从读者升级为写者是不允许的(尝试这样的行为会导致死锁)


  当锁被持有的时间相对较长,并且大部分操作都不会改变锁守护的资源,那么读写锁能够改进并发性。ReadWriteMap使用了ReentrantReadWriteLock来包装Map,使得它能够在多线程间


被安全的共享,并仍然能够避免 "读-写" 或者 ”写-写“冲突。显示中ConcurrentHashMap并发容器的性能已经足够好了,所以你可以是使用他,而不必使用这个新的解决方案,如果你需要并发的部分


只有哈希Map,但是如果你需要为LinkedHashMap这种可替换元素Map提供更好的并发访问,那么这项技术是非常有用的。


用读写锁包装的Map如下图:



读写锁的性能如下图:



 


总结:


  显式的Lock与内部锁相比提供了一些扩展的特性,包括处理不可用的锁时更好的灵活性,以及对队列行为更好的控制。但是ReentrantLock不能完全替代synchronized;只有当你需要


synchronized没能提供的特性时才应该使用。


  读-写锁允许多个读者并发访问被守护的对象,当访问多为读取数据结构的时候,它具有改进可伸缩性的潜力。


数据库层面上的锁——悲观锁和乐观锁


乐观锁:他对世界比较乐观,认为别人访问正在改变的数据的概率是很低的,所以直到修改完成准备提交所做的的修改到数据库的时候才会将数据锁住。完成更改后释放。


我想一下一个这样的业务场景:我们从数据库中获取了一条数据,我们正要修改他的数据时,刚好另外一个用户此时已经修改过了这条数据,这是我们是不知道别人修改过这条数据的。


  解决办法,我们可以在表中增加一个version字段,让这个version自增或者自减,或者用一个时间戳字段,这个时间搓字段是唯一的。我们写数据的时候带上version,也就是每个人更新的时候都会判断当前的版本号是否跟我查询出来得到的版本号是否一致,不一致就更新失败,一致就更新这条记录并更改版本号。


例子如下:


1.查询出商品信息
select (status,status,version) from t_goods where id=#{id}
2.根据商品信息生成订单
3.修改商品status为2
update t_goods
set status=2,version=version+1
where id=#{id} and version=#{version};


用户体验表现层面通常表现为系统繁忙之类的。


在这里还要注意乐观锁的一个细节:就是version字段要自增或者自减,否者会出现ABA问题


ABA问题:线程Thread1拿到了version字段为A,由于CAS操作(即先进行比较然后设值),线程Thread2先拿到的version,将version改成B,线程Thread3来拿到version,将version值又改回了A。此时Thread1的CAS(先比较后set值)操作结束了,继续执行,它发现version的值还是A,以为没有发生变化,所以就继续执行了。这个过程中,version从A变为B,再由B变为A就被形象地称为ABA问题了。


悲观锁也称排它锁,当事务在操作数据时把这部分数据进行锁定,直到操作完毕后再解锁,其他事务操作才可操作该部分数据。这将防止其他进程读取或修改表中的数据。


一般使用 select ...for update 对所选择的数据进行加锁处理,例如


select * from account where name=”JAVA” for update,


 这条sql 语句锁定了account 表中所有符合检索条件(name=”JAVA”)的记录。本次事务提交之前(事务提交时会释放事务过程中的锁),外界无法修改这些记录。


用户界面常表现为转圈圈等待。 


如果数据库分库分表了,不再是单个数据库了,那么我们可以用分布式锁,比如redis的setnx特性,zookeeper的节点唯一性和顺序性特性来做分布式锁。


首页 上一页 4 5 6 7 下一页 尾页 7/7/7
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇二叉搜索树介绍及其接口说明 下一篇在Kotlin中使用Gradle构建缓存

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目