Java NIO 高并发开发

news2024/11/17 6:47:12

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.coloradmin.cn/o/1142600.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

<多线程章节十> 定时器的使用方法以及定时器的模拟实现

文章目录 &#x1f490;专栏导读&#x1f4a1;Java标准库中的定时器类&#x1f4a1;模拟实现定时器 &#x1f490;专栏导读 本篇文章收录于多线程&#xff0c;也欢迎翻阅博主的其他文章&#xff0c;可能也会让你有不一样的收获&#x1f604; &#x1f342;JavaSE&#x1f337;多…

Studio One6.5新版本功能介绍及下载图文教程

studio one6更新了。studio one终于迎来了期待已久的6.5版本&#xff0c;增加了杜比全景声环绕声等混音模式&#xff0c;让我们混音更加方便&#xff01;Studio One 6破是一个功能完整的工作站&#xff0c;不止于专业的音乐制作和编辑&#xff0c;Studio One也是一个直播表演工…

计算机视觉 激光雷达结合无监督学习进行物体检测的工作原理

一、简述 激光雷达是目前正在改变世界的传感器。它集成在自动驾驶汽车、自主无人机、机器人、卫星、火箭等中。该传感器使用激光束了解世界,并测量激光击中目标返回所需的时间,输出是点云信息,利用这些信息,我们可以从3D点云中查找障碍物。 从自动驾驶汽车的角度看激光雷达…

MySQL启动后反复重新启动故障

MySQL版本为5.6.45 系统为Ubuntu 20.04 LTS 该服务器重启后&#xff0c;MySQL需要手动执行启动。 运行执行脚本后发现异常&#xff0c;如下图&#xff1a; 提示MySQL服务在不停重复启动。 反复使用ps -ef |grep mysql命令查看&#xff0c;发现mysql进程号一直在变化&#x…

ChatGLM推出第三代基座大模型在论文阅读、文档摘要和财报分析等方面提升超过50%推理成本降低一半...

“ 智谱AI发布了第三代基座大模型ChatGLM3&#xff0c;在模型性能、功能支持、开源序列等方面进行了全面升级。ChatGLM3在语义、数学、推理、代码、知识等不同角度的数据集上测评显示&#xff0c;具有在10B以下的基础模型中最强的性能。同时&#xff0c;ChatGLM3还支持多模态理…

数据库的概念和sql语句

数据&#xff1a;数字信息 据&#xff1a;就是属性 对一系列对象的具体属性的描述的集合 数据库&#xff1a;数据库就是用来组织&#xff08;各个数据之间是有关联。是按照规则组织起来的&#xff09;&#xff0c;存储和管理&#xff08;对数据的增删改查&#xff09;的仓库 …

推荐一本书《变速领导力》

大家好,这里是大话硬件。 今天想再给大家推荐一本书《变速领导力》。前段时间推荐的《横向领导力》在国庆假期内已经全部读完了,目前在进行二刷,边刷边做思维导图笔记。 就在二刷横向领导力的同时,假期还带了一本书回来《变速领导力》。这本书是在公司无意中看到其他组的…

【C语言_文件_进程_进程间通讯 常用函数/命令 + 实例】.md_update:23/10/27

目录&#xff1a; 文件相关命令进程相关命令getpid(); fork(); vfork();exit(6);wait(status); WEXITSTATUS(status);exec组函数 对比 system popen &#xff1a;精彩博文跳转&#xff1a; 进程间通讯精彩博文跳转pipe 无名管道mkfifo 有名管道消息队列共享内存_映射信号编程查…

139.【JUC并发编程-04】

JUC-并发编程04 (八)、共享模型之工具1.线程池(1).自定义线程池_任务数小于队列容量(2).自定义线程池_任务数大于队列容量(3).自定义线程池_拒绝策略 2.ThreadPoolExecutor(1).线程池状态(2).构造方法(3).newFixedThreadPool (固定大小线程池)(4).newCachedThreadPool (缓存线程…

企业内部IM即时聊天软件WorkPlus,自主可控的信创即时通讯IM

随着国家的发展发展&#xff0c;很多技术因为一些原因越来越受制于人&#xff0c;尤其是上游核心技术。为了解决这个问题&#xff0c;我国明确了“数字中国”建设战略&#xff0c;强调“自主”、“安全”、“可控”&#xff0c;不被“卡脖子”。在信创产业链的各环节中&#xf…

Linux中shell脚本中的变量

目录 一、变量的定义 二、shell脚本中变量的定义方法 1、变量名称 2、环境级别 3、用户级别 4、系统级别 5、删除设定的变量 三、变量的转译 1、转译 2、声明 3、变量的数组 四、Linux中命令的别名设定 五、用户环境变量的更改 脚本中的传参 1、非交互模式 2…

【VPX611】基于6U VPX总线架构的SATA3.0高性能数据存储板(3.2GByte/s存储带宽)

VPX611是一款基于6U VPX总线架构的高性能数据存储板&#xff0c;该板卡采用2片Xilinx Kintex-7系列FPGA作为主控单元&#xff0c;FPGA内嵌RAID控制器&#xff0c;最大支持8个mSATA盘&#xff0c;最大存储容量可以达到8TByte&#xff0c;持续数据写入带宽可以达到3.2GByte/s。板…

【运维】fstab,systemctl与rc.local启动顺序

前言: 在redis,mongo服务添加systemctl enable启动的情况下&#xff0c;redis和Mongo没有正常启动。排查日志得知,使用到的路径没有挂载。下面截图中的/var/lib/redis和mongo都是软连接&#xff0c;指向了一个服务器的本地盘。 经过排查/var/log/messages以及查阅相关日志得出:…

微积分(三) 不定积分和定积分

前言 微分法也有它的逆运算——积分法。我们已经知道&#xff0c;微分法的基本问题是研究如何从已知函数求出它的导函数&#xff0c;那么与之相反的问题是&#xff1a;求一个未知函数&#xff0c;使其导函数恰好是某一已知函数。 不定积分 假设已知函数A,一个个关于面积的函…

【Linux】NFS服务器搭建配置挂载(Linux挂载Windows目录)

本篇作用于Linux挂载Windows目录&#xff0c;如需要Linux挂载Linux目录请移步我的另一篇文章 http://t.csdnimg.cn/lVrC6http://t.csdnimg.cn/lVrC6 一、Windows端操作步骤 1、创建windows目录&#xff0c;右键目录>属性 2、共享选项>共享按钮>选择Administrator&…

【Python爬虫三天从0到1】Day1:爬虫核心

目录 1.HTTP协议与WEB开发 &#xff08;1&#xff09;简介 &#xff08;2&#xff09;请求协议和响应协议 2. requests&反爬破解 &#xff08;1&#xff09;UA反爬 &#xff08;2&#xff09;referer反爬 &#xff08;3&#xff09;cookie反爬 3.请求参数 &#x…

基于springboot实现校园交友网站管理系统项目【项目源码+论文说明】

基于springboot实现校园交友网站管理系统演示 摘要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生…

为什么说大模型微调是每个人都必备的核心技能?

▼最近直播超级多&#xff0c;预约保你有收获 近期直播&#xff1a;《基于开源 LLM 大模型的微调&#xff08;Fine tuning&#xff09;实战》 0 — 为什么要对 LLM 大模型进行微调&#xff08;Fine tuning&#xff09;&#xff1f; LLM 大模型&#xff08;比如&#xff1a;Chat…

python自动化测试(三):xpath获取元素

目录 前置代码 一、什么是xpath方式 二、通过xpath 单组属性名属性值 的方式进行元素定位 三、通过xpath的多组属性进行元素的定位 四、通过xpath文本值的方式进行元素定位 五、通过模糊的文本值方式进行元素定位 前置代码 # codingutf-8 from selenium import webdrive…

export declare const TestService和export const TestService的区别

两者的主要区别在于导出方式的差异和访问方式的差异。 export declare const TestService&#xff1a;这种方式使用了export declare语法来导出一个常量TestService。export declare语法告诉编译器&#xff0c;此处的声明是供其他模块使用的&#xff0c;但是在当前模块中并没有…