使用Java 8和Lambda简化ReadWriteLock

考虑到旧版Java代码,无论您在哪里看,带有lambda表达式的Java 8绝对可以提高质量和可读性。 今天,让我们看一下ReadWriteLock以及如何使它使用起来更简单。 假设我们有一个称为Buffer的类,该类可以记住队列中的最后几条消息,对旧消息进行计数并丢弃。 实现非常简单:

public class Buffer {private final int capacity;private final Deque<String> recent;private int discarded;public Buffer(int capacity) {this.capacity = capacity;this.recent = new ArrayDeque<>(capacity);}public void putItem(String item) {while (recent.size() >= capacity) {recent.removeFirst();++discarded;}recent.addLast(item);}public List<String> getRecent() {final ArrayList<String> result = new ArrayList<>();result.addAll(recent);return result;}public int getDiscardedCount() {return discarded;}public int getTotal() {return discarded + recent.size();}public void flush() {discarded += recent.size();recent.clear();}}

现在我们可以putItem() ,但是内部recent队列将仅保留最后一个capacity元素。 但是,它也记住必须丢弃多少项以避免内存泄漏。 该类工作正常,但仅在单线程环境中有效。 我们使用不是线程安全的ArrayDeque和非同步的int 。 尽管对int读写是原子的,但不能保证更改在不同线程中可见。 同样,即使我们将线程安全的BlockingDequeAtomicInteger一起使用,我们仍然处于竞争状态的危险中,因为这两个变量彼此不同步。

一种方法是synchronize所有方法 ,但这似乎很严格。 此外,我们怀疑读取的数量大大超过写入的数量。 在这种情况下, ReadWriteLock是绝佳的选择。 它实际上包括两个锁-一个用于读取,一个用于写入。 实际上,它们都为同一把锁竞争,而同一把锁可以同时由一个作者或多个读者获得。 因此,当没有人在写并且只有写者偶尔阻塞所有读者时,我们可以进行并发读取。 使用synchronized将始终阻止所有其他对象,无论他们做什么。 ReadWriteLock的可悲部分是它引入了许多样板。 您必须显式打开一个锁,并记住在finally块中对其进行unlock() 。 我们的实现变得难以阅读:

public class Buffer {private final int capacity;private final Deque<String> recent;private int discarded;private final Lock readLock;private final Lock writeLock;public Buffer(int capacity) {this.capacity = capacity;recent = new ArrayDeque<>(capacity);final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();readLock = rwLock.readLock();writeLock = rwLock.writeLock();}public void putItem(String item) {writeLock.lock();try {while (recent.size() >= capacity) {recent.removeFirst();++discarded;}recent.addLast(item);} finally {writeLock.unlock();}}public List<String> getRecent() {readLock.lock();try {final ArrayList<String> result = new ArrayList<>();result.addAll(recent);return result;} finally {readLock.unlock();
}public int getDiscardedCount() {readLock.lock();try {return discarded;} finally {readLock.unlock();}}public int getTotal() {readLock.lock();try {return discarded + recent.size();} finally {readLock.unlock();}}public void flush() {writeLock.lock();try {discarded += recent.size();recent.clear();} finally {writeLock.unlock();}}}

这是在八月8日之前完成的方式。有效,安全且丑陋。 但是,使用lambda表达式,我们可以将横切关注点包装在这样的实用程序类中:

public class FunctionalReadWriteLock {private final Lock readLock;private final Lock writeLock;public FunctionalReadWriteLock() {this(new ReentrantReadWriteLock());}public FunctionalReadWriteLock(ReadWriteLock lock) {readLock = lock.readLock();writeLock = lock.writeLock();}public <T> T read(Supplier<T> block) {readLock.lock();try {return block.get();} finally {readLock.unlock();}}public void read(Runnable block) {readLock.lock();try {block.run();} finally {readLock.unlock();}}public <T> T write(Supplier<T> block) {writeLock.lock();try {return block.get();} finally {writeLock.unlock();}
public void write(Runnable block) {writeLock.lock();try {block.run();} finally {writeLock.unlock();}}}

如您所见,我们包装了ReadWriteLock并提供了一组可使用的实用程序方法。 原则上,我们希望传递RunnableSupplier<T> (具有单个T get()方法的接口),并确保调用它时已被适当的锁包围。 我们可以编写完全相同的包装器类,而无需使用lambda,但是使用它们可以大大简化客户端代码:

public class Buffer {private final int capacity;private final Deque<String> recent;private int discarded;private final FunctionalReadWriteLock guard;public Buffer(int capacity) {this.capacity = capacity;recent = new ArrayDeque<>(capacity);guard = new FunctionalReadWriteLock();}public void putItem(String item) {guard.write(() -> {while (recent.size() >= capacity) {recent.removeFirst();++discarded;}recent.addLast(item);});}public List<String> getRecent() {return guard.read(() -> {return recent.stream().collect(toList());});}public int getDiscardedCount() {return guard.read(() -> discarded);}public int getTotal() {return guard.read(() -> discarded + recent.size());}public void flush() {guard.write(() -> {discarded += recent.size();recent.clear();});}}

看看我们如何调用guard.read()guard.write()传递应该受到保护的代码段? 看起来很整洁。 顺便说一句,您是否注意到我们如何使用stream()将任何集合转换为任何其他集合(在这里: Deque into List stream() ? 现在,如果我们提取几个内部方法,则可以使用方法引用来进一步简化lambda:

public void flush() {guard.write(this::unsafeFlush);
}private void unsafeFlush() {discarded += recent.size();recent.clear();
}public List<String> getRecent() {return guard.read(this::defensiveCopyOfRecent);
}private List<String> defensiveCopyOfRecent() {return recent.stream().collect(toList());
}

这只是利用lambda表达式来改进现有代码和库的众多方法之一。 我们真的很高兴他们终于进入Java语言了,同时已经出现在其他数十种JVM语言中。

翻译自: https://www.javacodegeeks.com/2014/03/simplifying-readwritelock-with-java-8-and-lambdas.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/363986.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[导入]C#好书盘点【月儿原创】

C#好书盘点【月儿原创】 文章来源:http://blog.csdn.net/21aspnet/archive/2007/07/07/1682200.aspx 转载于:https://www.cnblogs.com/zhaoxiaoyang2/archive/2007/07/08/816177.html

岁月如歌,人生如诗

虎跃千山龙腾海&#xff0c;春满家园喜满怀。新的一年&#xff0c;孕育着新的生命&#xff1b;新的一年&#xff0c;掸去了飞雪的扬花&#xff0c;满心的惬意告诉我们&#xff0c;所有的期盼与期望&#xff0c;一切的向往与憧憬正向着我们走近&#xff0c;向着春天融合。 ​ 新…

DOM编程以及domReady加载的几种方式

1&#xff0c;关于DOM编程 DOM编程主要是对dom树节点进行操作&#xff0c;所以你必须掌握基本的节点类型&#xff0c;如何去获取节点名字以及值&#xff08;这些相关知识你可以去网上查&#xff0c;这里推荐一个慕课学习网站->https://www.imooc.com/video/9491&#…

倒叙输出 php,php foreach正序倒序输出示例代码

实现代码&#xff1a;// 正序foreach($files as $file_num > $file) {if(is_file($directory.$file)){//$file iconv("gb2312","UTF-8",$file); //或者 iconv("gb2312","UTF-8",$value);$date substr($file,0,9);echo ;echo ;ech…

黑色系产业结构

转载于:https://www.cnblogs.com/luoluo-123/p/11143867.html

在Java 8 Lambda中创建自己的循环结构

Java没有简单的构造可以重复N次。 当然&#xff0c;我们可以创建一个for循环&#xff0c;但是很多时候我们甚至都不关心在循环中创建的变量。 我们只想重复一些代码N次&#xff0c;仅此而已。 使用Java 8中的lambda时&#xff0c;您可以尝试执行以下操作&#xff1a; public c…

Smart Form Tutorial(适用新手学习)

发现Smart Form在ECC6中和4.6C相比改变了不少&#xff0c;最近重新研究了一下。help.sap.com上的文档基本上是针对新特性的&#xff0c;不过例子却还是旧的。做个笔记省的以后找不到最新的example。最大的改变在Table上&#xff0c;现在table的header和footer比以前好做了。还是…

执行命令npm install XXX后仍然提示 Cannot find Module XXX

最近遇到一个问题&#xff0c;在服务器上配置完node环境后 执行npm start 命令后提示 Cannot find Module "Jquery" 然后就知道可能没有安装jquery 就继续在当前文件夹下执行 npm install jquery 但是再次执行后却仍然提示 Cannot find Module "Jquery"…

青蛙学Linux—Zabbix Web使用之Zabbix发现功能①自动网络发现

Zabbix的发现功能用于自动发现主机或者监控数据&#xff0c;包括以下三种发现类型&#xff1a; 自动网络发现&#xff08;Network discovery&#xff09;主动客户端自动注册&#xff08;Active agent auto-registration&#xff09;低级别发现&#xff08;low-level discovery&…

php 修改 wordpress,wordpress怎么编辑代码修改页面

wordpress是用PHP写的。PHP是服务器端执行脚本文件。然后到客户端(就是网页)生成html文件。你看到的html代码都是PHP程序在服务器端执行后生成的。若要修改代码主要是看想修改那一部分的内容。然后找到其对应的PHP代码.然后修改。在后台点击-->,就能看见你现在使用的wp主题的…

mpvue tabBar设定 app.json

1.微信小程序&#xff0c;设置src/app.json 中的tabBar 图标选择来自 iconfont 如图所示 小程序显示如下&#xff1a; 转载于:https://www.cnblogs.com/0909/p/11144861.html

JDK 8时代的抽象类与接口

在新的Java 8日期和时间API&#xff1a;Stephen Colebourne的访谈中 &#xff0c; Stephen Colebourne告诉Hartmut Schlosser &#xff1a;“我认为最重要的语言更改不是lambda&#xff0c;而是接口上的静态方法和默认方法。” Colebourne补充说&#xff1a;“添加默认方法消除…

察看linux内存使用情况

free功能说明&#xff1a;显示内存状态。语  法&#xff1a; free [-bkmotV][-s <间隔秒数>]补充说明&#xff1a;free指令会显示内存的使用情况&#xff0c;包括实体内存&#xff0c;虚拟的交换文件内存&#xff0c;共享内存区段&#xff0c;以及系统核心使用的缓冲区…

ajax请求拿到多条数据拼接显示在页面中

首先我们拿到的了一坨Json数据 如下 然后通过ajax请求拿到数据 在ajax的success方法中处理和使用数据&#xff1a; 其中包括&#xff1a; 用eval处理这种数据 var outStr eval(( data.data )); 用循环取出数据并使用 $.each(outStr,function(index){ console.log(outStr[i…

onesignal php,PHP FPM源代码反刍品味之五:信号signal处理

unix 的信号signal常用于进程管理.比如管理员或者操作系统通过向master进程实现重启和关闭服务&#xff0e;master进程通过向worker进程发信号管理worker进程&#xff0e;通常会在进程自定义信号处理函数,处理相关的逻辑.自定义信号处理函数,从使用者的角度看,很简单,有点像快捷…

【leetcode】657. Robot Return to Origin

Algorithm 【leetcode】657. Robot Return to Origin https://leetcode.com/problems/robot-return-to-origin/ 1&#xff09;problem There is a robot starting at position (0, 0), the origin, on a 2D plane. Given a sequence of its moves, judge if this robot ends up…

HTTP Developer's Handbook Part V: Security 读书笔记

Thus, the SSL handshake takes place once a TCP connection has been established between the Web client and Web server and before the initial HTTP request is sent.转载于:https://www.cnblogs.com/huyi/archive/2010/11/06/1870686.html

Spring 3.2矩阵变量是什么? - 第1部分

Spring 3.2引入了对处理“矩阵变量”的支持&#xff0c;并且可能像大多数开发人员一样&#xff0c;我从未听说过它们。 因此&#xff0c;经过一番研究&#xff0c;我对这个博客的了解是什么&#xff0c;以及您可以如何使用它们。 和往常一样&#xff0c;如果我错了&#xff0c;…

登录界面点击登录后如何延迟提示成功的div的显示时间并跳转

需求&#xff1a; 在登录页面点击sign in跳转到下个页面之前&#xff0c;我需要显示成功的窗口2秒然后自动关闭 那我们来研究下setTimeout: 关于这个setTimeout首先下面的代码实现的是两秒之后再显示SuccLogin窗体。 setTimeout(function () {$(".SuccLogin").sho…

MSN和QQ文件传输速度解析

基本上就是说msn传输文件是使用TCP&#xff0c;而QQ使用UDP&#xff0c;这就是两者传输速率的区别…… 发现很多情况下&#xff0c;msn传输文件比qq要慢&#xff0c;倒不是说msn没有快的时候&#xff0c;但是大部分的时候是真的比QQ慢&#xff0c;连我这种神经比较大条的人都注…