当前位置: 首页 > news >正文

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详解

1.概述 java.util.concurrent.Exchanger。这在Java中作为两个线程之间交换对象的公共点。 2.Exchanger简介 Exchanger类可用于在两个类型为T的线程之间共享对象。该类仅提供了一个重载的方法exchange(T t)。 当调用exchanger时&#xff0c;它会等待成对的另一个线程也调用它…...

‘再战千问:启程你的提升之旅‘,如何更好地提问?

例如&#xff0c;很多时候我们提出一些问题&#xff0c;然而通义千问提供的答案&#xff0c;并非完全符合我们的期望。这并非由于通义千问的智能程度不足&#xff0c;而是提问者的“提问技巧”尚未掌握得当。 难道提问还需要讲究艺术性吗&#xff1f;确实如此。今天&#xff0c…...

java SSM社区文化服务管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计

一、源码特点 java SSM社区文化服务管理系统是一套完善的web设计系统&#xff08;系统采用SSM框架进行设计开发&#xff0c;springspringMVCmybatis&#xff09;&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的 源代码和数据库&#xff0c;系统主…...

go执行静态二进制文件和执行动态库文件

目的和需求&#xff1a;部分go的核心文件不开源&#xff0c;例如验证&#xff0c;主程序核心逻辑等等 第一个想法&#xff0c;把子程序代码打包成静态文件&#xff0c;然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…...

通过示例解释序列化和反序列化-Java

序列化和反序列化是Java&#xff08;以及通常的编程&#xff09;中涉及将对象转换为字节流&#xff0c;以及反之的过程。当你需要传输或存储对象的状态时特别有用&#xff0c;比如将其通过网络发送或持久化到文件中。 序列化&#xff1a; 定义&#xff1a;序列化是将对象的状…...

k8s源码阅读环境配置

源码阅读环境配置 k8s代码的阅读可以让我们更加深刻的理解k8s各组件的工作原理&#xff0c;同时提升我们Go编程能力。 IDE使用Goland&#xff0c;代码阅读环境需要进行如下配置&#xff1a; 从github上下载代码&#xff1a;https://github.com/kubernetes/kubernetes在GOPATH目…...

Java JDBC整合(概述,搭建,PreparedStatement和Statement,结果集处理)

一、JDBC的概述&#xff1a; JDBC&#xff1a;是一种执行sql语句的Java APL&#xff0c;可以为多种关系类型数据库提供统一访问&#xff0c;它由一组用Java语言编写的类和接口组成。有了JDBC&#xff0c;Java人员只需要编写一次程序就可以访问不同的数据库。 JDBC APL&#xf…...

Nginx 负载均衡集群 节点健康检查

前言 正常情况下&#xff0c;nginx 做反向代理负载均衡的话&#xff0c;如果后端节点服务器宕掉的话&#xff0c;nginx 默认是不能把这台服务器踢出 upstream 负载集群的&#xff0c;所以还会有请求转发到后端的这台服务器上面&#xff0c;这样势必造成网站访问故障 注&#x…...

uniapp 多轴图,双轴图,指定哪几个数据在哪个轴上显示

这里使用的在这里导入&#xff0c; 秋云 ucharts echarts 高性能跨全端图表组件 - DCloud 插件市场 这里我封装成一个组件&#xff0c;自适应的&#xff0c;可以直接复制到自己的项目中 <template><qiun-data-charts type"mix":opts"opts":cha…...

Kotlin 协程 supervisorScope {} 运行崩溃解决

前言 简单介绍supervisorScope函数&#xff0c;它用于创建一个使用了 SupervisorJob 的 coroutineScope&#xff0c; 该作用域的特点&#xff1a;抛出的异常&#xff0c;不会 连锁取消 同级协程和父协程。 看过很多 supervisorScope {} 文档的使用&#xff0c;我照抄一摸一样…...

【Spring 篇】JdbcTemplate:轻松驾驭数据库的魔法工具

欢迎来到数据库的奇妙世界&#xff0c;在这里&#xff0c;我们将一同揭开Spring框架中JdbcTemplate的神秘面纱。JdbcTemplate是Spring提供的一个简化数据库操作的工具&#xff0c;它为我们提供了一种轻松驾驭数据库的魔法。本篇博客将详细解释JdbcTemplate的基本使用&#xff0…...

Web开发SpringBoot SpringMVC Spring的学习笔记(包含开发常用工具类)

开发框架学习笔记 一.Spring SpringMVC SpringBoot三者的联系SpringMVC工作原理 二.SpringBoot的学习2.1 注解2.1.1 SpringBoot的核心注解2.1.2 配置导入注解(简化Spring配置写XML的痛苦)Configuration和Bean(人为注册Spring 的 Bean)Import(补)ImportResource(补)AutowiredQua…...

微服务下的SpringSecurity认证端

从三板斧开始微服务下的SpringSecurity开始 一、引入组件包 <dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-oauth2</artifactId> </dependency> 二、创建适配器 AuthorizationServerConfig…...

苹果电脑菜单栏应用管理软件Bartender 4 mac软件特点

Bartender mac是一款可以帮助用户更好地管理和组织菜单栏图标的 macOS 软件。它允许用户隐藏和重新排列菜单栏图标&#xff0c;从而减少混乱和杂乱。 Bartender mac软件特点 菜单栏图标隐藏&#xff1a;Bartender 允许用户隐藏菜单栏图标&#xff0c;只在需要时显示。这样可以…...

笙默考试管理系统-MyExamTest----codemirror(65)

笙默考试管理系统-MyExamTest----codemirror&#xff08;65&#xff09; 目录 一、 笙默考试管理系统-MyExamTest----codemirror 二、 笙默考试管理系统-MyExamTest----codemirror 三、 笙默考试管理系统-MyExamTest----codemirror 四、 笙默考试管理系统-MyExamTest---…...

git在本地创建dev分支并和远程的dev分支关联起来

文章目录 git在本地创建dev分支并和远程的dev分支关联起来1. 使用git命令2. 使用idea2.1 先删除上面建的本地分支dev2.2 通过idea建dev分支并和远程dev分支关联 3. 查看本地分支和远程分支的关系 git在本地创建dev分支并和远程的dev分支关联起来 1. 使用git命令 git checkout…...

【C++】深入了解构造函数之初始化列表

目录 一、再谈构造函数 1、引入 1&#xff09;构造函数体赋值 2&#xff09;不同成员变量赋值 2、初始化列表 一、再谈构造函数 1、引入 1&#xff09;构造函数体赋值 在创建对象时&#xff0c;编译器通过调用构造函数&#xff0c;给对象中各个成员变量一个合适的初始值…...

差分--差分数组快速计算L到R值相加后的数组

目录 差分&#xff1a;思路代码&#xff1a; 原题链接 差分&#xff1a; 输入一个长度为 n 的整数序列。 接下来输入 m 个操作&#xff0c;每个操作包含三个整数 l,r,c &#xff0c;表示将序列中 [l,r] 之间的每个数加上 c 。 请你输出进行完所有操作后的序列。 输入格式 第…...

《NLP入门到精通》栏目导读(01/2)

一、说明 栏目《NLP入门到精通》本着从简到难得台阶式学习过度。将自然语言处理得知识贯穿过来。本栏目得前导栏目是《深度学习》、《pytorch实践》,因此,读者需要一定得深度学习基础,才能过度到此栏目内容。 二、博客建设理念 本博客基地,将建成人工智能领域的参考资料库;…...

three.js实现电子围栏效果(纹理贴图)

three.js实现电子围栏效果&#xff08;纹理贴图&#xff09; 实现步骤 围栏的坐标坐标转换为几何体顶点&#xff0c;uv顶点坐标加载贴图&#xff0c;移动 图例 代码 <template><div class"app"><div ref"canvesRef" class"canvas-…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器

第一章 引言&#xff1a;语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域&#xff0c;文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量&#xff0c;支撑着搜索引擎、推荐系统、…...

大模型多显卡多服务器并行计算方法与实践指南

一、分布式训练概述 大规模语言模型的训练通常需要分布式计算技术,以解决单机资源不足的问题。分布式训练主要分为两种模式: 数据并行:将数据分片到不同设备,每个设备拥有完整的模型副本 模型并行:将模型分割到不同设备,每个设备处理部分模型计算 现代大模型训练通常结合…...

tree 树组件大数据卡顿问题优化

问题背景 项目中有用到树组件用来做文件目录&#xff0c;但是由于这个树组件的节点越来越多&#xff0c;导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多&#xff0c;导致的浏览器卡顿&#xff0c;这里很明显就需要用到虚拟列表的技术&…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

论文阅读笔记——Muffin: Testing Deep Learning Libraries via Neural Architecture Fuzzing

Muffin 论文 现有方法 CRADLE 和 LEMON&#xff0c;依赖模型推理阶段输出进行差分测试&#xff0c;但在训练阶段是不可行的&#xff0c;因为训练阶段直到最后才有固定输出&#xff0c;中间过程是不断变化的。API 库覆盖低&#xff0c;因为各个 API 都是在各种具体场景下使用。…...

wpf在image控件上快速显示内存图像

wpf在image控件上快速显示内存图像https://www.cnblogs.com/haodafeng/p/10431387.html 如果你在寻找能够快速在image控件刷新大图像&#xff08;比如分辨率3000*3000的图像&#xff09;的办法&#xff0c;尤其是想把内存中的裸数据&#xff08;只有图像的数据&#xff0c;不包…...

通过MicroSip配置自己的freeswitch服务器进行调试记录

之前用docker安装的freeswitch的&#xff0c;启动是正常的&#xff0c; 但用下面的Microsip连接不上 主要原因有可能一下几个 1、通过下面命令可以看 [rootlocalhost default]# docker exec -it freeswitch fs_cli -x "sofia status profile internal"Name …...