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();}
在这里,我们有三个线程:reader
、processor
和writer
。它们共同作为一个单一的管道,在它们之间交换数据。
readerExchanger
在reader
和processor
线程之间共享,而writerExchanger
在processor
和writer
线程之间共享。
请注意,此处的示例仅用于演示。在创建无限循环时务必小心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时,它会等待成对的另一个线程也调用它…...

‘再战千问:启程你的提升之旅‘,如何更好地提问?
例如,很多时候我们提出一些问题,然而通义千问提供的答案,并非完全符合我们的期望。这并非由于通义千问的智能程度不足,而是提问者的“提问技巧”尚未掌握得当。 难道提问还需要讲究艺术性吗?确实如此。今天,…...

java SSM社区文化服务管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计
一、源码特点 java SSM社区文化服务管理系统是一套完善的web设计系统(系统采用SSM框架进行设计开发,springspringMVCmybatis),对理解JSP java编程开发语言有帮助,系统具有完整的 源代码和数据库,系统主…...

go执行静态二进制文件和执行动态库文件
目的和需求:部分go的核心文件不开源,例如验证,主程序核心逻辑等等 第一个想法,把子程序代码打包成静态文件,然后主程序执行 子程序 package mainimport ("fmt""github.com/gogf/gf/v2/os/gfile"…...
通过示例解释序列化和反序列化-Java
序列化和反序列化是Java(以及通常的编程)中涉及将对象转换为字节流,以及反之的过程。当你需要传输或存储对象的状态时特别有用,比如将其通过网络发送或持久化到文件中。 序列化: 定义:序列化是将对象的状…...

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

Java JDBC整合(概述,搭建,PreparedStatement和Statement,结果集处理)
一、JDBC的概述: JDBC:是一种执行sql语句的Java APL,可以为多种关系类型数据库提供统一访问,它由一组用Java语言编写的类和接口组成。有了JDBC,Java人员只需要编写一次程序就可以访问不同的数据库。 JDBC APL…...

Nginx 负载均衡集群 节点健康检查
前言 正常情况下,nginx 做反向代理负载均衡的话,如果后端节点服务器宕掉的话,nginx 默认是不能把这台服务器踢出 upstream 负载集群的,所以还会有请求转发到后端的这台服务器上面,这样势必造成网站访问故障 注&#x…...
uniapp 多轴图,双轴图,指定哪几个数据在哪个轴上显示
这里使用的在这里导入, 秋云 ucharts echarts 高性能跨全端图表组件 - DCloud 插件市场 这里我封装成一个组件,自适应的,可以直接复制到自己的项目中 <template><qiun-data-charts type"mix":opts"opts":cha…...
Kotlin 协程 supervisorScope {} 运行崩溃解决
前言 简单介绍supervisorScope函数,它用于创建一个使用了 SupervisorJob 的 coroutineScope, 该作用域的特点:抛出的异常,不会 连锁取消 同级协程和父协程。 看过很多 supervisorScope {} 文档的使用,我照抄一摸一样…...

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

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 软件。它允许用户隐藏和重新排列菜单栏图标,从而减少混乱和杂乱。 Bartender mac软件特点 菜单栏图标隐藏:Bartender 允许用户隐藏菜单栏图标,只在需要时显示。这样可以…...
笙默考试管理系统-MyExamTest----codemirror(65)
笙默考试管理系统-MyExamTest----codemirror(65) 目录 一、 笙默考试管理系统-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)构造函数体赋值 2)不同成员变量赋值 2、初始化列表 一、再谈构造函数 1、引入 1)构造函数体赋值 在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值…...
差分--差分数组快速计算L到R值相加后的数组
目录 差分:思路代码: 原题链接 差分: 输入一个长度为 n 的整数序列。 接下来输入 m 个操作,每个操作包含三个整数 l,r,c ,表示将序列中 [l,r] 之间的每个数加上 c 。 请你输出进行完所有操作后的序列。 输入格式 第…...

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

three.js实现电子围栏效果(纹理贴图)
three.js实现电子围栏效果(纹理贴图) 实现步骤 围栏的坐标坐标转换为几何体顶点,uv顶点坐标加载贴图,移动 图例 代码 <template><div class"app"><div ref"canvesRef" class"canvas-…...
Vue记事本应用实现教程
文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展:显示创建时间8. 功能扩展:记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

7.4.分块查找
一.分块查找的算法思想: 1.实例: 以上述图片的顺序表为例, 该顺序表的数据元素从整体来看是乱序的,但如果把这些数据元素分成一块一块的小区间, 第一个区间[0,1]索引上的数据元素都是小于等于10的, 第二…...
【杂谈】-递归进化:人工智能的自我改进与监管挑战
递归进化:人工智能的自我改进与监管挑战 文章目录 递归进化:人工智能的自我改进与监管挑战1、自我改进型人工智能的崛起2、人工智能如何挑战人类监管?3、确保人工智能受控的策略4、人类在人工智能发展中的角色5、平衡自主性与控制力6、总结与…...

CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
mongodb源码分析session执行handleRequest命令find过程
mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程,并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令,把数据流转换成Message,状态转变流程是:State::Created 》 St…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...

P3 QT项目----记事本(3.8)
3.8 记事本项目总结 项目源码 1.main.cpp #include "widget.h" #include <QApplication> int main(int argc, char *argv[]) {QApplication a(argc, argv);Widget w;w.show();return a.exec(); } 2.widget.cpp #include "widget.h" #include &q…...