《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁

摘要:
唯一可用于协调对共享对象的访问的机制是同步和易失性的。13.1锁和重入锁(p227)程序清单13-1中给出的锁接口定义了一组抽象锁操作。ReentrantLock支持lock界面中定义的所有锁获取模式。13.1.1轮询锁定和定时锁定(p228)定时和可轮询锁定获取模式通过tryLock方法实现。

第13章 显示锁

终于看到了这本书的最后一本分,呼呼呼,真不容易。其实说实在的,我不喜欢半途而废,有其开始,就一定要有结束,否则的话就感觉哪里乖乖的。

java5.0之前,在协调对共享对象的访问时可以使用的机制只有synchronized和volatile。java5.0增加了一种新的机制:ReentrantLock。与之前提到过的机制相反,ReentrantLock并不是一种替代内置锁的方法,而是当内置锁机制不适用时,作为一种可选择的高级功能。

13.1 Lock与ReentrantLock(p227)

 《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第1张

程序清单13-1中给出的Lock接口定义了一组抽象的加锁操作。与内置锁机制不同的是,Lock提供了一种无条件的,可轮询的,定时的以及可中断的锁获取操作,所有加锁和解锁操作都是显示的。

ReentrantLock实现了Lock接口(Reentrant:再进去,凹角,再进去的,凹角的),并提供了与synchronized相同的互斥性和内存可见性。ReentrantLock支持在Lock接口中定义的所有获取锁模式,并且与syncronized相比,他为处理锁的不可用性提供了更高的灵活性。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第2张

书上一段话就截了这部分,感觉这段有点翻译错误。程序清单13-2给出了Lock接口的标准使用形式。这种形式比使用内置锁复杂一些,必须在finally块中释放锁,否则如果早被保护的代码中抛出了异常,那么这个锁永远都无法释放。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第3张

ReentrantLock不能完全替代syncronized的原因:它更加危险,因为当程序的执行控制离开被保护的代码块时,不会自动清楚。虽然在finally块中释放锁并不困难,但也可能忘记。

13.1.1 轮询锁与定时锁(p228)

可定时的与可轮询的锁获取模式是由tryLock方法实现的,与无条件的锁获取模式相比,它具有更完善的错误恢复机制。如果不能获得所有需要的锁,那么可以使用可定时的锁或可轮询的锁获取方式,从而使你重新获得控制权,它会释放已经获得的锁,然后重新尝试获取所有锁。程序清单13-3给出了另一种方法来解决10.1.2节中动态顺序死锁的问题:使用tryLock来获取两个锁,如果不能同时获得,那么就回退并重新尝试。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第4张

  《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第5张

在实现具有时间限制的操作时,定时锁同样非常有用。当在带时间限制的操作中调用了一个阻塞方法时,它能根据剩余时间来提供一个时限。如果操作不能在指定时间内给出结果,那么使程序提前结束。当使用内置锁时,在开始请求锁后,这个锁操作将无法取消,因此内置锁很难实现带有时间限制的操作。

程序清单6-17的旅游门户网站示例中,为询价的每个汽车租赁公司都创建另一个独立的任务。询价操作包含某种基于网络的请求机制,例如web请求。但在询价操作中同样可能需要实现对紧缺资源的独占访问,例如通向公司的直连线路。9.5节介绍了确保对资源进行串行访问的方法:一个单线程的Executor。另一种方法是使用一个独占锁来保护对资源的访问。程序清单13-4试图在Lock保护的共享通信线路上发送一条消息,如果不能在指定时间完成,代码就会失败。定时的tryLock能够在这种带有时间限制的操作中实现独占行为。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第6张

13.1.2 可中断的锁获取操作(p230)

可中断的锁获取操作能在可取消的操作中使用加锁。7..6节给出了几种不能响应中断的机制,例如请求内置锁。这些不可中断的阻塞机制将使得实现可取消的任务变得复杂。lockInterruptibly方法能够在获得锁的同时保持对中断的响应,并且由于它包含在Lock中,因此无须创建其它类型的不可中断阻塞机制。来个例子:

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第7张

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第8张

13.1.3 非块结构加锁(p231)

采用11章中的锁分段技术来降低链表中锁的粒度,为每个链表节点使用一个独立的锁,使不同的线程能独立地对链表的不同部分进行操作。每个节点的锁将保护链接指针以及在该节点中存储的数据,只有这样,才能释放前一个节点上的锁。(连锁式加锁(Hand-Over-Hand Locking)||锁耦合(Lock Coupling))

13.2 性能考虑因素

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第9张

上图的原因是:java 6使用了改进后的算法来管理内置锁,使得内置锁和ReentrantLock在java6上的性能差异不是很大,而在java 5上就差很多了。

13.3 公平性

在ReentrantLock的构造函数中提供了两种公平性的选择:创建一个非公平的锁(默认)或者一个公平的锁。在公平的锁上,线程将按照它们发出请求的顺序来获得锁,但在非公平的锁上,则允许“插队”:当一个线程请求非公平的锁时,如果在发出请求的同时该锁的状态变为可用,那么这个线程将跳过队列中所有等待线程并获得这个锁。(在Semaphore中同样可以选择采用公平或非公平的获取顺序)。在公平的锁中,如果有另一个线程持有这个锁或者有其他线程在队列中等待这个锁,那么新发出请求的线程将被放入队列中。在非公平的锁中,只有当锁被某个线程持有时,新发出请求的线程才会被放入队列中。(即使对于公平锁而言,可轮询的tryLock任然会“插队”)

图13-2给出了Map的性能测试,并比较由公平的以及非公平的ReentrantLock包装的HashMap性能。从图中可以看出,公平性把性能降低了越两个数量级。不必要的话,不要为公平性付出代价。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第10张

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第11张

 

13.4 在synchronized和ReentrantLock之间进行选择(p234)

ReentrantLock在性能上似乎优于内置锁,但与显示锁相比,内置锁仍然具有很大的优势。内置锁为许多开发人员所熟悉,并且简介紧凑,而且许多现有的程序都已经使用了内置锁,如果将这两种机制混合使用,那么不仅容易令人困惑,也容易发生错误。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第12张

 

13.5 读 — 写锁

ReentrantLock实现了一种标准的互斥锁:每次只能有一个线程能持有ReentrantLock。但对于维护数据完整性来说,互斥锁通常是一种过于强硬的加锁规则,因此也就不必要地限制了并发性。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第13张

意思就是这个锁允许的情况只有两种:要么全是读操作,要么就是一个写操作,两者不能同时进行。

在程序清单13-6的ReadWriteLock中暴露了两个Lock对象,其中一个用于读操作,而另一个用于写操作。要读取由ReadWriteLock保护的数据,必须首先获得读取锁,当需要修改ReadWriteLock保护的数据时,必须首先获得写入锁。尽管这两个锁看上去是彼此独立的,但读取锁和写入锁知识 读—写 锁对象的不同视图。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第14张

在 读 — 写 锁实现的加锁策略中,允许多个读操作同时进行,但每次只允许一个写操作。与Lock一样,ReadWriteLock可以采用多种不同的实现方式,这些方式在性能,调度保证,获取优先性,公平性以及加锁语义等方面可能有所不同。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第15张

在读取锁和写入锁之间的交互可以采用多种实现方式。ReadWriteLock中的一些可选实现包括:

 《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第16张

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第17张

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第18张

当锁的持有是将较长并且大部分操作都不会修改被守护的资源时,那么读—写锁能提高并发性。在程序清单13-7的ReadWriteMap中使用了ReentrantReadWriteLock来包装Map,从而使它能在多个读线程之间被安全地共享,并且仍然能避免“读-写”或“写-写”冲突。在实现中,ConcurrentHashMap的性能已经很好了,一次如果只需要一个并发的基于散列映射,那么就可以使用ConcurrentHashMap来代替这种方法,但如果需要多另一种Map实现提供并发性更高的访问,那么可是使用这项技术。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第19张

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第20张

图13-3给出了分别用ReentrantLock和ReadWriteLock来封装ArrayList的吞吐量比较,每个操作随机地选择一个值并在容器中查找这个值,并且只有少量的操作会修改这个容器中的内容。

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第21张


小结:

《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁第22张

免责声明:文章转载自《《java并发编程实战》读书笔记10--显示锁Lock,轮询、定时、读写锁》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇docker~环境变量到底怎么用logstash 读取MySQL数据到elasticsearch 相差8小时解决办法下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

关于一个简单接口的高并发测试与优化记录

目的 通过测试,了解高并发需求的各处细节,寻找制约因素;为软件框架 和 硬件架构提供优化参考。 前述 优化前,目标接口在测试环境的qps为160左右 目标接口的内部逻辑 处理前1:开始计时 处理前2:较验IP白名单[rpc] 处理: 查询数据库并缓存 处理后1:结束计时;提交性能报告[rpc];提交输入输出日志[rpc] 日志通过RPC,最终写入数据...

读懂IL代码就这么简单(二)

一 前言   IL系列 第一篇写完后 得到高人指点,及时更正了文章中的错误,也使得我写这篇文章时更加谨慎,自己在了解相关知识点时,也更为细致。个人觉得既然做为文章写出来,就一定要保证比较高的质量,和正确率 。感谢 @冰麟轻武 的指点 你没有看第一篇?  点这里看第一篇 读懂IL代码就这么简单(一)   IL指令大全 :IL指令详解 IL反编译工具: ILD...

腾讯WeTest性能测试工具PerfDog获得中国计量科学研究院权威测试认证

2020年11月,由国家最高的计量科学研究中心和国家级法定计量技术机构中国计量科学研究院下设单位国家计量器具软件测评中心为腾讯WeTest质量开放平台的性能测试工具PerfDog颁发了“测评证书”,兹认定“移动全平台性能测试分析专家PerfDog(下称PerfDog),各项性能基准值可靠,且具有良好的数据准确性、数据完整性以及较高的数据稳定性”。 这是Pe...

HTTP3.0(QUIC的实现机制)

回顾HTTP2.0 HTTP1.1在应用层以纯文本的形式进行通信,每次通信都要带完整的HTTP的头,而且不考虑pipeli模式的化,每次的过程总是像上面描述的那样一去一回。那样在实时性、并发想上都存在问题 头部压缩:HTTP2.0会对HTTP的头进行一定的压缩,将原来每次都要携带的大量key value在两端建立一个索引表,对相同的头只发送索引表中的索引...

顺手的Linux发行版及其工具推荐

从Windows切换到Linux已经有半年多的时间了,简单给大家推荐一些个人感觉不错的软件,主要都是和开发相关的通用软件~~~ 0.archlinux   挑一个比较顺手的linux发行版当然是首要任务了,我的开发硬件平台是笔记本,所以我主要看重这几个方面(以我用过的ubuntu/debian/centos/fedora/opensuse/archlinu...

Java Concurrency API 中的 Lock 接口(Lock interface) 是什么?对比同步它有什么优势?

Lock 接口比同步方法和同步块提供了更具扩展性的锁操作。 他们允许更灵活的结构,可以具有完全不同的性质,并且可以支持多个相关类的  条件对象。 它的优势有: 可以使锁更公平  可以使线程在等待锁的时候响应中断  可以让线程尝试获取锁,并在无法获取锁的时候立即返回或者等待一段时间  可以在不同的范围,以不同的顺序获取和释放锁  整体上来说 Lock...