java-Exchanger详解

2024-01-11 01:52
文章标签 java 详解 exchanger

本文主要是介绍java-Exchanger详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

1.概述

java.util.concurrent.Exchanger。这在Java中作为两个线程之间交换对象的公共点。

2.Exchanger简介

Exchanger类可用于在两个类型为T的线程之间共享对象。该类仅提供了一个重载的方法exchange(T t)。

当调用exchanger时,它会等待成对的另一个线程也调用它。在这一点上,第二个线程发现第一个线程正在等待其对象。线程交换它们持有的对象并发出交换信号,然后它们可以返回。

让我们看一个例子,以理解两个线程之间使用Exchanger进行消息交换:

 @Test
public void givenThreads_whenMessageExchanged_thenCorrect() {Exchanger<String> exchanger = new Exchanger<>();Runnable taskA = () -> {try {String message = exchanger.exchange("from A");assertEquals("from B", message);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}};Runnable taskB = () -> {try {String message = exchanger.exchange("from B");assertEquals("from A", message);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}};CompletableFuture.allOf(runAsync(taskA), runAsync(taskB)).join();}

在这里,我们有两个线程使用共同的Exchanger交换彼此之间的消息。让我们看一个例子,在这个例子中,我们从主线程与一个新线程交换对象:

@Test
public void givenThread_WhenExchangedMessage_thenCorrect() throws InterruptedException, ExecutionException {Exchanger<String> exchanger = new Exchanger<>();Runnable runner = () -> {try {String message = exchanger.exchange("from runner");assertEquals("to runner", message);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}};CompletableFuture<Void> result = runAsync(runner);String msg = exchanger.exchange("to runner");assertEquals("from runner", msg);result.join();}

请注意,我们需要先启动runner线程,然后在主线程中调用exchange()

还要注意,如果第二个线程在超时时间内未达到交换点,第一个线程的调用可能会超时。第一个线程应等待多长时间可以使用重载的exchange(T t, long timeout, TimeUnit timeUnit)来控制。

3.无GC数据交换

Exchanger可以用于创建通过一个线程向另一个线程传递数据的管道类型的模式。

   private static final int BUFFER_SIZE = 100;@Testpublic void givenData_whenPassedThrough_thenCorrect() throws InterruptedException, ExecutionException {Exchanger<Queue<String>> readerExchanger = new Exchanger<>();Exchanger<Queue<String>> writerExchanger = new Exchanger<>();int counter = 0;Runnable reader = () -> {Queue<String> readerBuffer = new ConcurrentLinkedQueue<>();while (true) {readerBuffer.add(UUID.randomUUID().toString());if (readerBuffer.size() >= BUFFER_SIZE) {try {readerBuffer = readerExchanger.exchange(readerBuffer);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}}}};Runnable processor = () -> {Queue<String> processorBuffer = new ConcurrentLinkedQueue<>();Queue<String> writerBuffer = new ConcurrentLinkedQueue<>();try {processorBuffer = readerExchanger.exchange(processorBuffer);while (true) {writerBuffer.add(processorBuffer.poll());if (processorBuffer.isEmpty()) {try {processorBuffer = readerExchanger.exchange(processorBuffer);writerBuffer = writerExchanger.exchange(writerBuffer);} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}}}} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}};Runnable writer = () -> {Queue<String> writerBuffer = new ConcurrentLinkedQueue<>();try {writerBuffer = writerExchanger.exchange(writerBuffer);while (true) {System.out.println(writerBuffer.poll());if (writerBuffer.isEmpty()) {writerBuffer = writerExchanger.exchange(writerBuffer);}}} catch (InterruptedException e) {Thread.currentThread().interrupt();throw new RuntimeException(e);}};CompletableFuture.allOf(runAsync(reader), runAsync(processor), runAsync(writer)).get();}

在这里,我们有三个线程:readerprocessorwriter。它们共同作为一个单一的管道,在它们之间交换数据。

readerExchangerreaderprocessor线程之间共享,而writerExchangerprocessorwriter线程之间共享。

请注意,此处的示例仅用于演示。在创建无限循环时务必小心while(true)。另外,为保持代码的可读性,我们省略了一些异常处理。

通过重用缓冲区来交换数据的这种模式允许减少垃圾回收。exchange方法返回相同的队列实例,因此这些对象不会被垃圾回收。与任何阻塞队列不同,Exchanger不会创建任何用于保存和共享数据的节点或对象。

创建这样的管道类似于Disruptor模式,其中一个关键区别是,Disruptor模式支持多个生产者和消费者,而Exchanger可以在一对生产者和消费者之间使用。

4.总结

因此,Java中的Exchanger是什么,它是如何工作的,我们看到了如何使用Exchanger类。此外,我们创建了一个管道,并演示了线程之间无GC的数据交换。

这篇关于java-Exchanger详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/592771

相关文章

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

Java实现删除文件中的指定内容

《Java实现删除文件中的指定内容》在日常开发中,经常需要对文本文件进行批量处理,其中,删除文件中指定内容是最常见的需求之一,下面我们就来看看如何使用java实现删除文件中的指定内容吧... 目录1. 项目背景详细介绍2. 项目需求详细介绍2.1 功能需求2.2 非功能需求3. 相关技术详细介绍3.1 Ja

springboot项目中整合高德地图的实践

《springboot项目中整合高德地图的实践》:本文主要介绍springboot项目中整合高德地图的实践,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一:高德开放平台的使用二:创建数据库(我是用的是mysql)三:Springboot所需的依赖(根据你的需求再

spring中的ImportSelector接口示例详解

《spring中的ImportSelector接口示例详解》Spring的ImportSelector接口用于动态选择配置类,实现条件化和模块化配置,关键方法selectImports根据注解信息返回... 目录一、核心作用二、关键方法三、扩展功能四、使用示例五、工作原理六、应用场景七、自定义实现Impor

SpringBoot3应用中集成和使用Spring Retry的实践记录

《SpringBoot3应用中集成和使用SpringRetry的实践记录》SpringRetry为SpringBoot3提供重试机制,支持注解和编程式两种方式,可配置重试策略与监听器,适用于临时性故... 目录1. 简介2. 环境准备3. 使用方式3.1 注解方式 基础使用自定义重试策略失败恢复机制注意事项

一文深入详解Python的secrets模块

《一文深入详解Python的secrets模块》在构建涉及用户身份认证、权限管理、加密通信等系统时,开发者最不能忽视的一个问题就是“安全性”,Python在3.6版本中引入了专门面向安全用途的secr... 目录引言一、背景与动机:为什么需要 secrets 模块?二、secrets 模块的核心功能1. 基

一文详解MySQL如何设置自动备份任务

《一文详解MySQL如何设置自动备份任务》设置自动备份任务可以确保你的数据库定期备份,防止数据丢失,下面我们就来详细介绍一下如何使用Bash脚本和Cron任务在Linux系统上设置MySQL数据库的自... 目录1. 编写备份脚本1.1 创建并编辑备份脚本1.2 给予脚本执行权限2. 设置 Cron 任务2

SpringBoot整合Flowable实现工作流的详细流程

《SpringBoot整合Flowable实现工作流的详细流程》Flowable是一个使用Java编写的轻量级业务流程引擎,Flowable流程引擎可用于部署BPMN2.0流程定义,创建这些流程定义的... 目录1、流程引擎介绍2、创建项目3、画流程图4、开发接口4.1 Java 类梳理4.2 查看流程图4

一文详解如何在idea中快速搭建一个Spring Boot项目

《一文详解如何在idea中快速搭建一个SpringBoot项目》IntelliJIDEA作为Java开发者的‌首选IDE‌,深度集成SpringBoot支持,可一键生成项目骨架、智能配置依赖,这篇文... 目录前言1、创建项目名称2、勾选需要的依赖3、在setting中检查maven4、编写数据源5、开启热