java网络编程-nio学习:阻塞和非阻塞

news2024/12/24 0:25:41

一、阻塞

  • 阻塞模式下,相关方法都会导致线程暂停

    • ServerSocketChannel.accept 会在没有连接建立时让线程暂停

    • SocketChannel.read 会在没有数据可读时让线程暂停

    • 阻塞的表现其实就是线程暂停了,暂停期间不会占用 cpu,但线程相当于闲置

  • 单线程下,阻塞方法之间相互影响,几乎不能正常工作,需要多线程支持

  • 但多线程下,有新的问题,体现在以下方面

    • 32 位 jvm 一个线程 320k,64 位 jvm 一个线程 1024k,如果连接数过多,必然导致 OOM,并且线程太多,反而会因为频繁上下文切换导致性能降低

    • 可以采用线程池技术来减少线程数和线程上下文切换,但治标不治本,如果有很多连接建立,但长时间 inactive,会阻塞线程池中所有线程,因此不适合长连接,只适合短连接。

服务端事例代码:

// 使用 nio 来理解阻塞模式, 单线程
// 0. ByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(16);
// 1. 创建了服务器
ServerSocketChannel ssc = ServerSocketChannel.open();

// 2. 绑定监听端口
ssc.bind(new InetSocketAddress(8080));

// 3. 连接集合
List<SocketChannel> channels = new ArrayList<>();
while (true) {
    // 4. accept 建立与客户端连接, SocketChannel 用来与客户端之间通信
    log.debug("connecting...");
    SocketChannel sc = ssc.accept(); // 阻塞方法,线程停止运行
    log.debug("connected... {}", sc);
    channels.add(sc);
    for (SocketChannel channel : channels) {
        // 5. 接收客户端发送的数据
        log.debug("before read... {}", channel);
        channel.read(buffer); // 阻塞方法,线程停止运行
        buffer.flip();
        debugRead(buffer);
        buffer.clear();
        log.debug("after read...{}", channel);
    }
}

客户端:

SocketChannel sc = SocketChannel.open();
sc.connect(new InetSocketAddress("localhost", 8080));
System.out.println("waiting...");

二、非阻塞

  • 非阻塞模式下,相关方法都会不会让线程暂停

    • 在 ServerSocketChannel.accept 在没有连接建立时,会返回 null,继续运行

    • SocketChannel.read 在没有数据可读时,会返回 0,但线程不必阻塞,可以去执行其它 SocketChannel 的 read 或是去执行 ServerSocketChannel.accept

    • 写数据时,线程只是等待数据写入 Channel 即可,无需等 Channel 通过网络把数据发送出去

  • 但非阻塞模式下,即使没有连接建立,和可读数据,线程仍然在不断运行,白白浪费了 cpu

  • 数据复制过程中,线程实际还是阻塞的(AIO 改进的地方)

服务器端demo代码,客户端代码不变

// 使用 nio 来理解非阻塞模式, 单线程
// 0. ByteBuffer
ByteBuffer buffer = ByteBuffer.allocate(16);
// 1. 创建了服务器
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false); // 非阻塞模式
// 2. 绑定监听端口
ssc.bind(new InetSocketAddress(8080));
// 3. 连接集合
List<SocketChannel> channels = new ArrayList<>();
while (true) {
    // 4. accept 建立与客户端连接, SocketChannel 用来与客户端之间通信
    SocketChannel sc = ssc.accept(); // 非阻塞,线程还会继续运行,如果没有连接建立,但sc是null
    if (sc != null) {
        log.debug("connected... {}", sc);
        sc.configureBlocking(false); // 非阻塞模式
        channels.add(sc);
    }
    for (SocketChannel channel : channels) {
        // 5. 接收客户端发送的数据
        int read = channel.read(buffer);// 非阻塞,线程仍然会继续运行,如果没有读到数据,read 返回 0
        if (read > 0) {
            buffer.flip();
            debugRead(buffer);
            buffer.clear();
            log.debug("after read...{}", channel);
        }
    }
}

三、多路复用

单线程可以配合 Selector 完成对多个 Channel 可读写事件的监控,这称之为多路复用。

  • 多路复用仅针对网络 IO、普通文件 IO 没法利用多路复用

  • 如果不用 Selector 的非阻塞模式,线程大部分时间都在做无用功,而 Selector 能够保证

    • 有可连接事件时才去连接

    • 有可读事件才去读取

    • 有可写事件才去写入

      • 限于网络传输能力,Channel 未必时时可写,一旦 Channel 可写,会触发 Selector 的可写事件

好处

  • 一个线程配合 selector 就可以监控多个 channel 的事件,事件发生线程才去处理。避免非阻塞模式下所做无用功

  • 让这个线程能够被充分利用

  • 节约了线程的数量

  • 减少了线程上下文切换

 

创建

Selector selector = Selector.open();

绑定 Channel 事件

也称之为注册事件,绑定的事件 selector 才会关心

channel.configureBlocking(false);
SelectionKey key = channel.register(selector, 绑定事件);
  • channel 必须工作在非阻塞模式

  • FileChannel 没有非阻塞模式,因此不能配合 selector 一起使用

  • 绑定的事件类型可以有

    • connect - 客户端连接成功时触发

    • accept - 服务器端成功接受连接时触发

    • read - 数据可读入时触发,有因为接收能力弱,数据暂不能读入的情况

    • write - 数据可写出时触发,有因为发送能力弱,数据暂不能写出的情况

监听 Channel 事件

可以通过下面三种方法来监听是否有事件发生,方法的返回值代表有多少 channel 发生了事件

方法1,阻塞直到绑定事件发生  (常用)

int count = selector.select();

方法2,阻塞直到绑定事件发生,或是超时(时间单位为 ms)

int count = selector.select(long timeout);

方法3,不会阻塞,也就是不管有没有事件,立刻返回,自己根据返回值检查是否有事件

int count = selector.selectNow();

select 何时不阻塞

  • 事件发生时

    • 客户端发起连接请求,会触发 accept 事件

    • 客户端发送数据过来,客户端正常、异常关闭时,都会触发 read 事件,另外如果发送的数据大于 buffer 缓冲区,会触发多次读取事件

    • channel 可写,会触发 write 事件

    • 在 linux 下 nio bug 发生时

  • 调用 selector.wakeup()

  • 调用 selector.close()

  • selector 所在线程 interrupt

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

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

相关文章

Learning C++ No.11【string类实现】

引言&#xff1a; 北京时间&#xff1a;2023/2/19/8:48&#xff0c;昨天更新了有关进程状态的博客&#xff0c;然后在休息的时候&#xff0c;打开了腾讯视屏&#xff0c;然后看到了了一个电视剧&#xff0c;导致上头&#xff0c;从晚上6点看到了10点&#xff0c;把我宝贵的博客…

vue(5)

文章目录1. 监测数据原理1.1 通过问题引出1.2 开始1.3 Vue.set() 方法1.4 vue 监视 数组1.5 小练习2. 收集表数据3. 过滤器4. 内置指令4.1 v-text4.2 v-html4.3 v-cloak4.4 v-once4.5 v-pre1. 监测数据原理 1.1 通过问题引出 1.2 开始 要想解决上面的这个问题 &#xff0c;需要…

python基于django幼儿园管理系统

目录 1 绪论 1 1.1课题背景 1 1.2课题研究现状 1 1.3初步设计方法与实施方案 2 1.4本文研究内容 2 2 系统开发环境 4 2.1 JAVA简介 4 2.2MyEclipse环境配置 4 2.3 B/S结构简介 4 2.4MySQL数据库 5 2.5 SPRINGBOOT框架 5 3 系统分析 6 3.1系统可行性分析 6 3.1.1经济可行性 6 3…

【2022.12.9】Lammps+Python 在计算g6(r)时遇到的问题

目录写在前面绘制g6( r )执行步骤【updated】如何检查图像的正确性&#xff1a;不是编程问题&#xff0c;而是数学问题的一个小bug废稿2则&#xff1a;写在前面 全部log&#xff1a; 【2022.11.16】LammpsPythonMATLAB在绘制维诺图时遇到的问题 绘制g6( r )执行步骤【updated…

Eureka原理浅析

文章目录1.简介2.组件2.1 Eureka Server2.1.1 主要功能2.1.2 自我保护机制2.1.3 数据同步方式2.1.4 Server的多级缓存和Client实例过期策略2.2 Eureka Client3.补充3.1 CAP偏重点3.2 功能扩展性3.3 工作流程1.简介 Eureka是Netflix开发的服务发现框架&#xff0c;本身是基于RE…

SegNeXt: 重新思考基于卷积注意力的语义分割

论文信息 论文名称&#xff1a;SegNeXt: Rethinking Convolutional Attention Design for Semantic Segmentation 项目GitHub&#xff1a; GitHub - Visual-Attention-Network/SegNeXt: Official Pytorch implementations for "SegNeXt: Rethinking Convolutional Atten…

ESP-C3入门11. 创建最基本的HTTP请求

ESP-C3入门11. 创建最基本的HTTP请求一、menuconfig配置二、配置 CMakeLists1. 设置项目的额外组件目录2. 设置头文件搜索目录三、在 ESP32 上执行 HTTP 请求的基本步骤1. 创建 TCP 连接2. 设置 HTTP 请求3. 发送 HTTP 请求4. 接收 HTTP 响应5. 处理 HTTP 响应6. 关闭 TCP 连接…

35岁以上的大龄测试员们,后来都干什么去了?

为什么软件测试行业看不见白发苍苍的软件测试员?大龄测试员都去哪里了?各个公司会辞退大龄测试员吗? 如果一位 50 多岁的测试员申请 20 多岁或 30 多岁的职位&#xff0c;有多少公司会雇用他们呢?关于这个问题&#xff0c;有很多流言传说&#xff0c;也有一些残酷的现实。…

努力优化和改造不好的环境,去设计新的、积极的、适合自己的环境

你知道环境对你的影响有多大吗&#xff1f;自己的的社交圈也是一个环境如果你待在一个只知道吃喝玩乐&#xff0c;不思进取&#xff0c;天天玩手机、打游戏的圈子里那你很大程度也会被影响&#xff0c;因为你不跟他们一起你就融入不进去&#xff0c;就会被孤立&#xff0c;很多…

优秀蓝牙耳机推荐,热销不错的四款蓝牙耳机推荐

蓝牙耳机作为目前最流行的数码产品&#xff0c;受到很多人追捧&#xff0c;蓝牙耳机摆脱了有线蓝牙耳机的束缚&#xff0c;能够更好听歌打游戏&#xff0c;随时取用&#xff0c;更为便利&#xff0c;当然&#xff0c;随着耳机的大幅度创新&#xff0c;也导致很多人在选购耳机的…

内网渗透(四十三)之横向移动篇-SMB远程执行命令横向移动

系列文章第一章节之基础知识篇 内网渗透(一)之基础知识-内网渗透介绍和概述 内网渗透(二)之基础知识-工作组介绍 内网渗透(三)之基础知识-域环境的介绍和优点 内网渗透(四)之基础知识-搭建域环境 内网渗透(五)之基础知识-Active Directory活动目录介绍和使用 内网渗透(六)之基…

前端性能优化的一些技巧(90% chatGpt生成)

终于弄好了chatGpt的账号&#xff0c;赶紧来体验一波。先来一波结论&#xff0c;这篇文章的主要内容来源&#xff0c;90%是用chatGpt生成的。先上chatGpt的生成的结果&#xff1a;作为一名懒惰的程序员&#xff0c;chatGpt会帮助我变得更懒...&#xff0c;好了下面开始文章的正…

GEE学习笔记 六十八:【GEE之Python版教程二】配置Python开发环境

这一篇内容主要讲解两部分内容&#xff0c;第一部分是本地python开发环境的配置&#xff0c;第二部分是GEE的python开发环境配置。我这里做的所有的操作都是在我的Mac电脑上做的&#xff0c;Windows上操作类似&#xff0c;如果有不清楚的可以自行搜索相关操作步骤。 第一部分&…

pytorch零基础实现语义分割项目(四)——模型训练与预测

模型训练与预测项目列表前言损失函数one_hotDice LossFocal Loss模型参数与训练预测项目列表 语义分割项目&#xff08;一&#xff09;——数据概况及预处理 语义分割项目&#xff08;二&#xff09;——标签转换与数据加载 语义分割项目&#xff08;三&#xff09;——语义…

winserver服务器硬盘满了怎么清理? 服务器硬盘空间不足清理方法

本文主要介绍我在维护windows server服务器期间总结的一些磁盘清理方式。如对您有所帮助&#xff0c;不甚荣幸。 文章目录一、C盘清理1. System32的日志文件2. IIS的日志文件3. .Net Framework的缓存文件4. 清理其他不必要文件5. 虚拟内存从c盘移到其他硬盘二、其他软件清理1. …

【离散数学】4. 图论

1.数理逻辑 2. 集合论 3. 代数系统 4. 图论 图&#xff1a;点边边与点的映射函数 连通性与判别 欧拉图与哈密尔顿图 二分图和平面图与欧拉公式 树及生成树 单源点最短路径&#xff1a;Dijkstra算法 对偶图 4. 图论 4.1 图的基本概念 4.1.1 图 一个图G是一个三重组 <V(G),E…

【LeetCode】No.232. 用栈实现队列 -- Java Version

题目链接&#xff1a;https://leetcode.cn/problems/implement-queue-using-stacks/ 1. 题目介绍&#xff08;232. 用栈实现队列&#xff09; 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff…

两年外包生涯做完,感觉自己废了一半....

先说一下自己的情况。大专生&#xff0c;17年通过校招进入湖南某软件公司&#xff0c;干了接近2年的点点点&#xff0c;今年年上旬&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01;而我已经在一个企业干了五年的功能测试…

慕了没?3年经验,3轮技术面+1轮HR面,拿下字节30k*16薪offer

前段时间有个朋友出去面试&#xff0c;这次他面试目标比较清晰&#xff0c;面的都是业务量大、业务比较核心的部门。前前后后去了不少公司&#xff0c;几家大厂里&#xff0c;他说给他印象最深的是字节3轮技术面1轮HR面&#xff0c;他最终拿到了30k*16薪的offer。第一轮主要考察…

MyBatis-Plus详细讲解(整合spring Boot)

哈喽&#xff0c;大家好&#xff0c;今天带大家了解的是MyBatis-Plus&#xff08;简称 MP&#xff09;&#xff0c;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。首先说一下MyBatis-Plus的愿景是什么&…