考虑到旧版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

使用Java 8和Lambda简化ReadWriteLock相关推荐

  1. java lambda使用_使用Java 8和Lambda简化ReadWriteLock

    java lambda使用 考虑到旧版Java代码,无论您在哪里看,带有lambda表达式的Java 8绝对可以提高质量和可读性. 今天,让我们看一下ReadWriteLock以及如何使它使用起来更简 ...

  2. Java:Lambda简化匿名内部类

    Java内部类详解 Java:Lambda简化匿名内部类 Lambda概述.基本用法 Lambda表达式是JDK 8开始后的一种新语法形式. 作用:简化函数式接口的匿名内部类的写法. Lambda表达 ...

  3. Java Lambda简化Comparator接口匿名内部类写法

    Lambda简化Comparator接口匿名内部类写法 //Lambda简化Comparator接口匿名内部类写法public static void main(String[] args) {Lis ...

  4. 带有Java 8,lambda表达式和Mockito-Java8附加组件的更紧凑的Mockito

    Mockito-Java8是一组Mockito附加组件,它们利用Java 8和lambda表达式使Mockito的模拟更加紧凑. 在2015年初,我进行了简短的演讲, Java 8为测试带来了力量! ...

  5. comparator接口_8000字长文让你彻底了解 Java 8 的 Lambda、函数式接口、Stream 用法和原理

    我是风筝,公众号「古时的风筝」.一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...

  6. 【java】理解和运用Java中的Lambda

    1.概述 转载:理解和运用Java中的Lambda 前提 回想一下,JDK8是2014年发布正式版的,到现在为(2020-02-08)止已经过去了5年多.JDK8引入的两个比较强大的新特性是Lambd ...

  7. Java多线程:Lambda 表达式

    什么是Lambda 表达式 Lambda 表达式,也可称为闭包,它是Java 8 发布的最重要新特性. Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中). 使用 Lambda 表 ...

  8. 十三、Java高级特性 Lambda表达式 | 接口组成更新 | 方法引用 | 函数式接口

    文章目录 十三.Java高级特性 1.Lambda表达式 1.1体验Lambda表达式[理解] 1.2Lambda表达式的标准格式[理解] 1.3Lambda表达式练习1[应用] 1.4Lambda表 ...

  9. 【Java 8】Lambda表达式

    本文参考书籍<Java 8实战>,陆明刚.劳佳  译,如有侵权,请联系删除! 我们了解了利用行为参数化来传递代码有助于应对不断变化的需求,它允许我们定义一个代码块来表示一个行为,然后传递它 ...

最新文章

  1. JAVA常见工具配置
  2. k8s强制删除一直处于terminating状态的pod
  3. apache服务器配置tls_Apache服务器配置https
  4. 京东:Flink SQL 优化实战
  5. c语言课程设计加密程序,C语言课程设计文件加密解密.doc
  6. 牛客题霸 [ 未排序数组中累加和为给定值的最长子数组长度] C++题解/答案
  7. [vue] vue使用v-for遍历对象时,是按什么顺序遍历的?如何保证顺序?
  8. java dao 单元测试_Spring Service、Dao进行Junit单元测试
  9. [Unity]导入插件出现编译错误的解决办法:在工程关闭时重新添加一次插件
  10. c# 多线程 --Mutex(互斥锁) 【转】
  11. 黑客都是使用哪些方法入侵我们电脑的
  12. java生成和识别二维码
  13. 安全清理大部分的C盘内存(一般10GB以上)
  14. 花钱购买C语言教程,秘籍:小白从零开始玩转C语言教程,足足300集
  15. 捷联惯导基础知识解析之二(捷联惯导更新算法和误差方程)
  16. NCL绘制色斑图-多要素叠加
  17. 高通camera结构(摄像头基础介绍)
  18. No current assignment for partition 解决
  19. 分享 :CSS常见面试题
  20. 【车辆计数】基于光流法实现车辆检测计数matlab 源码

热门文章

  1. 利用赫夫曼编码进行数据解压
  2. ListView条目中有CheckBox点击事件失效问题
  3. Spring Boot 入门 IDEA 版本 2小时学会springBoot 代码上传至gitee 或者github 事务没做出来
  4. 架构师成长之路(内附推荐书籍)
  5. Mysql优化(三):优化order by
  6. 混合多云架构_使用混合多云每个人都应避免的3个陷阱(第2部分)
  7. eclipse neon_在自定义Java 9映像上运行Eclipse Neon
  8. facelets_Java EE 8中的MVC 1.0:使用Facelets入门
  9. mysql重置增量_摆脱困境:在每种测试方法之前重置自动增量列
  10. jooq 执行sql_使用jOOQ和Java 8的CompletableFuture进行异步SQL执行