Java NIO 高并发开发

Java NIO 高并发开发

前言

Java NIO(New I/O)相比于传统的Java I/O(BIO)在高并发开发方面具有以下优势:

  1. 非阻塞模式:Java NIO使用非阻塞的I/O操作,允许一个线程管理多个通道(Channel),并且在没有数据可读写时不会阻塞线程。这意味着一个线程可以同时处理多个连接,而不需要为每个连接创建一个独立的线程,从而大大减少了线程的数量和上下文切换的开销。

  2. 选择器(Selector):Java NIO提供了Selector机制,通过Selector可以同时监控多个通道的事件(如可读、可写、连接等)。一个Selector可以管理多个通道,通过单个线程监听多个通道上的事件,避免了为每个通道创建独立线程的开销。

  3. 缓冲区(Buffer):Java NIO使用缓冲区进行数据的读写操作,通过将数据从通道读取到缓冲区中,或者将数据从缓冲区写入到通道中,可以提高数据的处理效率。此外,缓冲区还可以进行批量读写操作,减少了系统调用的次数,提高了性能。

  4. 零拷贝(Zero-copy):Java NIO支持零拷贝技术,即数据在内核空间和用户空间之间的传输可以避免数据的拷贝。在传统的Java I/O中,数据需要从内核缓冲区拷贝到用户缓冲区,然后再进行处理,而Java
    NIO可以直接在内核缓冲区和用户缓冲区之间进行操作,减少了数据拷贝的开销。

综上所述,Java
NIO通过非阻塞模式、选择器、缓冲区和零拷贝等特性,使得一个线程可以同时管理多个通道,大大提高了系统的并发性能。相比于传统的Java
I/O,它能更有效地利用系统资源,减少线程数量和上下文切换的开销,适用于高并发的网络应用程序开发。然而,需要注意的是,Java
NIO相对复杂,需要处理多线程同步、数据一致性等问题,因此在使用时需要谨慎处理各种可能的事件和异常情况。
在我发这篇文章之前,我已经发过NIO的基础用法和全套NIO用法,可以看之前我发的文章Java NIO 和Java NIO 开发
在这里插入图片描述

一,Java NIO 高并发示例代码模板

当然,我会为你提供带有注释的Java NIO高并发开发示例代码。以下是一个考虑到并发、线程安全、锁竞争、异常处理、线程池配置和内存管理的示例代码:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class NIOConcurrencyExample {private static final int BUFFER_SIZE = 1024;private static final int THREAD_POOL_SIZE = 10;public static void main(String[] args) throws IOException {// 创建 Selector 对象Selector selector = Selector.open();// 创建 ServerSocketChannel 并绑定端口ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();serverSocketChannel.bind(new InetSocketAddress(8080));serverSocketChannel.configureBlocking(false);serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);// 创建线程池ExecutorService executorService = Executors.newFixedThreadPool(THREAD_POOL_SIZE);while (true) {// 等待就绪的通道int readyChannels = selector.select();if (readyChannels == 0) {continue;}// 获取就绪通道的 SelectionKey 集合Set<SelectionKey> selectedKeys = selector.selectedKeys();Iterator<SelectionKey> keyIterator = selectedKeys.iterator();while (keyIterator.hasNext()) {SelectionKey key = keyIterator.next();if (key.isAcceptable()) {// 接受新的客户端连接请求ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();SocketChannel clientChannel = serverChannel.accept();clientChannel.configureBlocking(false);clientChannel.register(selector, SelectionKey.OP_READ);} else if (key.isReadable()) {// 处理读取事件的线程executorService.execute(() -> {try {SocketChannel clientChannel = (SocketChannel) key.channel();ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);int bytesRead = clientChannel.read(buffer);// 处理读取到的数据while (bytesRead > 0) {buffer.flip();// TODO: 处理数据逻辑buffer.clear();bytesRead = clientChannel.read(buffer);}if (bytesRead == -1) {clientChannel.close();}} catch (IOException e) {e.printStackTrace();}});}keyIterator.remove();}}}
}

这个示例代码中,我添加了详细的Java注释,以解释代码的功能和关键部分。请注意,注释中的TODO标记表示您需要根据实际需求添加适当的业务逻辑。

此示例代码考虑了以下方面:

  • 并发和线程安全:使用线程池来处理客户端的读取操作,确保多个客户端可以并发处理而不会阻塞主线程。
  • 锁竞争:由于使用了线程池,每个客户端的读取操作在独立的线程中执行,减少了锁竞争的可能性。
  • 异常处理:在读取操作中捕获并处理IOException异常,以避免程序崩溃或出现不可预料的错误。
  • 线程池配置:使用Executors.newFixedThreadPool()方法创建指定大小的线程池,您可以根据需要进行调整。
  • 内存管理:使用ByteBuffer来管理内存,通过allocate()方法分配缓冲区,通过flip()和clear()方法重置缓冲区。

请注意,这只是一个示例代码,实际应用中可能需要根据具体情况进行调整和优化。

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

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

相关文章

systrace/perfetto如何看surfaceflinger的vsync信号方法-android framework实战车载手机系统开发

背景&#xff1a; hi&#xff0c;粉丝朋友们&#xff1a; 大家好&#xff01;近期分享了surfaceflinger相关的一些blog&#xff0c;有同学就对相关的一些内容产生了一些疑问。 比如&#xff1a;vsync查看问题&#xff0c;即怎么才可以说是vsync到来了。 比如perfetto中surfac…

打破信息孤岛,如何从API、数据中台突围

“烟囱”林立&#xff0c;零售企业“数据孤岛”现象突出 所谓数据孤岛&#xff0c;是指零售企业不同组织机构之间、不同部门之间或不同软件之间的数据无法连接互动&#xff0c;数据信息不能共享&#xff0c;设计、管理、生产的数据不能相互交流&#xff0c;数据出现脱节的现象…

vue项目中内嵌iframe,打包上线时候iframe地址如何写?

vue项目中内嵌iframe&#xff0c;打包上线时候iframe地址如何写 一、项目结构1.内嵌的iframe文件位置2.打包后的iframe的位置 二、代码 前提描述&#xff0c;项目是用webpack打包的&#xff0c;内嵌一个完整的js小组件 一、项目结构 1.内嵌的iframe文件位置 2.打包后的iframe的…

归结原理、归结演绎推理

主要内容 归结演绎推理范式子句与子句集将谓词公式转化为子句集命题逻辑鲁宾逊归结原理 归结演绎推理 定理证明的实质是对前提P和结论Q证明P →Q的永真性应用反证法&#xff0c;欲证明P →Q&#xff0c;只要证明 P∧~Q 等价于 F鲁宾逊归结原理对机械化推理有重大突破鲁宾逊归…

吴恩达《机器学习》1-3:监督学习

一、监督学习 例如房屋价格的数据集。在监督学习中&#xff0c;我们将已知的房价作为"正确答案"&#xff0c;并将这些价格与房屋的特征数据一起提供给学习算法。学习算法使用这些已知答案的数据来学习模式和关系&#xff0c;以便在未知情况下预测其他房屋的价格。这就…

牛客网刷题-(7)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

蓝桥杯每日一题2023.10.26

测试次数 - 蓝桥云课 (lanqiao.cn) 题目描述 题目分析 对于本题我们可以使用动态规划来分析 dp[i][j]代表剩余i层&#xff0c;j台手机的情况下对应的测试数量 分类进行讨论一下&#xff1a; 1.当只剩下一台手机的时候&#xff0c;只能从第一层一层一层往上尝试&#xff0c…

AT32固件库外设使用,ArduinoAPI接口移植,模块化

目录 一、ArduinoAPI移植一、通用定时器使用1.计时1.2.ETR外部时钟计数4.ArduinoAPI - timer 三、ADC1.ADC初始化&#xff08;非DMA&#xff09;2.ADC_DMA 规则通道扫描 六、USB HID IAP1.准备好Bootloader和app2.配置好时钟&#xff0c;一定要打开USB3.将生成的时钟配置复制到…

Unity编辑器扩展之自定义Inspector面板

首先找到的是这个[CustomEditor(typeof(Class), true)]&#xff0c;这个东西能够自己绘制在Inspector视图的显示规则&#xff0c;但是&#xff01;如果这个类被另一个类持有&#xff0c;他就没作用了&#xff0c; 效果图&#xff1a; 1.对CustomClass类编辑自定义面板 2. 对M…

美摄AI商品图解决方案

电子商务时代&#xff0c;商品图片的质量直接影响着消费者的购买决策。一张高质量的商品图片不仅能够吸引消费者的注意力&#xff0c;还能够提升品牌形象&#xff0c;从而提高销售额。然而&#xff0c;拍摄高质量的商品图片并不是一件容易的事情&#xff0c;它需要专业的摄影技…

【阅读和学习代码】VoxelNet

文章目录 将点特征 转换为 voxel 特征稀疏张量 到 稠密张量&#xff0c;反向索引参考博客 将点特征 转换为 voxel 特征 https://github.com/skyhehe123/VoxelNet-pytorch/blob/master/data/kitti.py 【Python】np.unique() 介绍与使用 self.T &#xff1a; # maxiumum numbe…

什么是时序图,看了你就明白

目录 前言: 什么是时序图: 时序图的组成元素&#xff1a; 1. 角色(Actor) 2. 对象(Object) 3. 生命线(LifeLine) 4. 激活期(Activation) 5. 消息类型(Message) 6.组合片段(Combined fragment) 时序图的绘制规则:​ 绘制时序图的3步&#xff1a; 1.划清边界&#xf…