nio多线程版本

多线程多路复用

多线程NIO,,就是多个线程,每个线程上都有一个Selector,,,比如说一个系统中一个线程用来接收请求,,剩余的线程用来读写数据,,每个线程独立干自己的事,,,
一个线程的多路复用,,虽然不会卡住,,但是执行单个事件的时间过长,也会长时间卡在那里,,,需要开启多个线程,,但是多个线程中执行代码的顺序是不可控的,,一般是在主线程接收到一个新的连接之后,再用子线程中的Selector去关注返回的SocketChannel,
selector.select()是在子线程中执行的,,,关注事件是在主线程执行的,,如果子线程中的selector.select()先阻塞住了,,关注事件的代码就必须等到有新的事件到来,才会往下执行

如果子线程想要监听到这个事件,,注册事件的代码就必须在 selector.select()阻塞的代码的前面,,,但是这个是不可控的,,就需要使用selector.wakeup() 唤醒这个selector.select() 阻塞,,唤醒了之后,后面关注事件的代码就执行了,后面监听到这个关注事件,就会去处理

public class MultiThreadServer {public static void main(String[] args) throws IOException {Thread.currentThread().setName("boss");ServerSocketChannel ssc = ServerSocketChannel.open();ssc.configureBlocking(false);Selector boss = Selector.open();SelectionKey bossKey = ssc.register(boss, 0, null);bossKey.interestOps(SelectionKey.OP_ACCEPT);ssc.bind(new InetSocketAddress(8080));// 可用的核心数   ===》 如果在docker上,,拿到的是物理cpu个数,,而不是容器申请时的个数,,,在jdk10才修复int i1 = Runtime.getRuntime().availableProcessors();Worker[] workers = new Worker[2];for (int i = 0; i < workers.length; i++) {workers[i] = new Worker("worker-"+i);}AtomicInteger index =new AtomicInteger(0);while (true){boss.select();Iterator<SelectionKey> iter = boss.selectedKeys().iterator();while (iter.hasNext()){SelectionKey key = iter.next();iter.remove();if (key.isAcceptable()){SocketChannel sc = ssc.accept();System.out.println("客户端已进入"+sc);sc.configureBlocking(false);System.out.println("before register...");// 轮询选择器,选择一个线程执行workers[index.getAndIncrement() % workers.length].register(sc);//                    worker01.register(sc);// 前面初始化 selector.select()阻塞了
//                    SelectionKey scKey = sc.register(worker01.selector, 0, null);
//                    scKey.interestOps(SelectionKey.OP_READ);System.out.println("after register...");
//                    sc.register()}}}}static class Worker implements Runnable{private Thread thread;private Selector selector;private String name;private ConcurrentLinkedQueue<Runnable> queue = new ConcurrentLinkedQueue<>();private volatile  boolean start = false;// 是否初始化public Worker(String name) {this.name = name;}// 初始化线程和Selectorpublic void register(SocketChannel sc) throws IOException {if (!start){selector = Selector.open();thread = new Thread(this,name);thread.start();start = true;}queue.add(()->{try {sc.register(selector,SelectionKey.OP_READ);} catch (ClosedChannelException e) {throw new RuntimeException(e);}});selector.wakeup();//            sc.register(selector,SelectionKey.OP_READ);
//            // 唤醒阻塞,,, 阻塞住了,,下面的register就无法到达
//            selector.wakeup();}@Overridepublic void run() {while (true){try {selector.select();// 最开始的时候  ,,,run如果先执行,,,queue里面是空的,,注册逻辑放在select()前面也是一样不会将 socketChannel注册进去,, 需要唤醒Runnable task = queue.poll();if (task != null){task.run();}Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();while (iterator.hasNext()){SelectionKey key = iterator.next();iterator.remove();if (key.isReadable()){ByteBuffer buffer = ByteBuffer.allocate(16);SocketChannel channel = (SocketChannel) key.channel();channel.read(buffer);System.out.println(Thread.currentThread().getName()+"name");debugAll(buffer);}else if(key.isWritable()){}}} catch (IOException e) {throw new RuntimeException(e);}}}}
}
名词
  • 阻塞IO: 用户线程会一直等待,直到数据准备好,才返回,,,就是线程停止,等待数据

  • 非阻塞IO: 用户程序空间操作系统的内核空间 ==》 操作系统会立即返回,,用户线程始终在运行,并没有停下来

  • 多路复用: 通过Selector监测事件,,检测到有事件就会到操作系统内核空间去执行

  • 同步: 线程自己去获取结果

  • 异步: 线程自己不去获取结果,,由另一个线程送结果 (至少有两个线程)

  • 异步IO: 异步都是非阻塞的,,一个线程执行,,通过另一个线程返回结果,,,

阻塞IO是同步的,,也叫同步阻塞,,,
非阻塞IO也是同步的,也叫同步非阻塞
多路复用也是同步的,,只是将所有的事件都集中到一起处理

零拷贝

在这里插入图片描述

一般的文件读取,都是要经过内核空间用户空间 ,再从用户空间 拷贝到 缓冲区, 一个文件要拷贝很多次,,才能发送出去,,
零拷贝: 就是让文件拷贝,不再经过用户空间,,直接就用操作系统内核空间里面的数据。。
零拷贝适合那种小文件拷贝,,因为大文件会占用很多内核缓冲区,,可能会影响别的IO操作

// 堆外内存(direct buffer) : 直接分配在堆外的内存,减少从堆内存到直接内存的拷贝
ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
AIO(Asynchronous IO) 异步输入输出

非阻塞IO,,需要一个回调函数,去传递 执行完成之后返回的结果

public class Demo01 {/*** linux 对异步IO不友好,,, 底层只是用多路复用模拟了一个异步IO,,,性能上没有优势* window系统通过IOCP实现了真正的异步IO***/public static void main(String[] args) throws IOException, InterruptedException {CountDownLatch countDownLatch = new CountDownLatch(1);// 异步IO必须是多个线程,,,一个线程发起,一个线程送结果Path path = Paths.get("/Users/chenjie/code/learn/learn-netty/learn-netty/netty01/src/main/resources/word.txt");System.out.println(Files.exists(path));try (AsynchronousFileChannel channel = AsynchronousFileChannel.open(path, StandardOpenOption.READ)) {ByteBuffer buffer = ByteBuffer.allocate(8);ByteBuffer attachBuffer = ByteBuffer.allocate(8);System.out.println("read begin:"+Thread.currentThread().getName());/*** params: ByteBuffer* params2: 读取的起始位置* params3: 附件 : 万一一次读不完,,需要一个bytebuffer接着读* params4: 真正结果出来了,调用这个回调方法*/channel.read(buffer,0,attachBuffer,new CompletionHandler<Integer, ByteBuffer>(){@Overridepublic void completed(Integer result, ByteBuffer attachment) {// 当你的文件正确读取完毕后attachment.flip();debugAll(attachment);System.out.println(Thread.currentThread().getName()+"hehe");countDownLatch.countDown();}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {System.out.println("exc = " + exc);System.out.println(exc.getMessage()+"e");}});System.out.println("read finished");countDownLatch.await();} catch (IOException e) {throw new RuntimeException(e);}}}

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

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

相关文章

LabVIEW DataSocket 通信库详解

dataskt.llb 是 LabVIEW 2019 内置的核心函数库之一&#xff0c;位于 vi.lib\Platform\ 目录下&#xff0c;专注于 DataSocket 技术的实现。DataSocket 是 NI 提供的网络通信协议&#xff0c;支持跨平台、跨设备的实时数据共享&#xff0c;广泛应用于远程监控、分布式系统集成等…

【UI设计——视频播放界面分享】

视频播放界面设计分享 在本次设计分享中&#xff0c;带来一个视频播放界面的设计作品。 此界面采用了简洁直观的布局。顶部是导航栏&#xff0c;包含主页、播放、搜索框等常见功能&#xff0c;方便用户快速找到所需操作。搜索框旁输入 “萌宠成长记”&#xff0c;体现了对特定内…

论coding能力 new bing 对比 chatgpt

近日需要编程计算每个月的第二个星期二是哪一天&#xff0c;因为那一天需要做一件重要的事情&#xff0c;我想在这个日期做一个提醒&#xff0c;于是把这个重任交给当下最火的AI&#xff0c;微软new bing和chatGPT&#xff0c;实验对比结果如下&#xff1a;微软new bing会给你参…

leetcode第39题组合总和

原题出于leetcode第39题https://leetcode.cn/problems/combination-sum/description/题目如下&#xff1a; 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以…

计算机毕业设计SpringBoot+Vue.js社区智慧养老监护管理平台(源码+文档+PPT+讲解)

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长联系方式的名片&#xff01; 作者简介&#xff1a;Java领…

Linux:动静态库

库&#xff1a;Linux&#xff1a;静态库&#xff08;libxxxx.a&#xff09;和动态库(libxxxx.so) 库&#xff1a;windows静态库(xxxx.lib)和动态库 (xxxx.dll) ldd 可以看自己所依赖的目标文件 /lib64/libc.so.6------>这是c标准库 file code &#xff08;动态库&…

在Pycharm中将ui文件修改为py文件

在Pycharm中将ui文件修改为py文件 有些时候&#xff0c;我们需要把QTDesigner生成的.ui文件修改为.py文件 在一些教程中&#xff0c;通常使用cmd打开终端修改&#xff0c;或者是有一些人写了一些脚本来修改 这里我们可以使用pycharm来快速的修改 首先&#xff0c;我们在pyc…

RabbitMQ面试题及原理

RabbitMQ使用场景&#xff1a; 异步发送&#xff08;验证码、短信、邮件…&#xff09;MYSQL和Redis, ES之间的数据同步分布式事务削峰填谷 1. 消息可靠性&#xff08;不丢失&#xff09; 消息丢失场景&#xff1a; RabbitMQ-如何保证消息不丟失&#xff1f; 开启生产者确…

GDidees CMS v3.9.1本地文件泄露漏洞(CVE-2023-27179)

漏洞简介&#xff1a; GDidees CMS v3.9.1及更低版本被发现存在本地文件泄露漏洞&#xff0c;漏洞通过位于 /_admin/imgdownload.php 的 filename 参数进行利用。 漏洞环境&#xff1a; 春秋云镜中的漏洞靶标&#xff0c;CVE编号为CVE-2023-27179 漏洞复现: 进入靶场发现没…

金融项目实战

测试流程 测试流程 功能测试流程 功能测试流程 需求评审制定测试计划编写测试用例和评审用例执行缺陷管理测试报告 接口测试流程 接口测试流程 需求评审制定测试计划分析api文档编写测试用例搭建测试环境编写脚本执行脚本缺陷管理测试报告 测试步骤 测试步骤 需求评审 需求评…

本地部署 DeepSeek:从 Ollama 配置到 Spring Boot 集成

前言 随着人工智能技术的迅猛发展&#xff0c;越来越多的开发者希望在本地环境中部署和调用 AI 模型&#xff0c;以满足特定的业务需求。本文将详细介绍如何在本地环境中使用 Ollama 配置 DeepSeek 模型&#xff0c;并在 IntelliJ IDEA 中创建一个 Spring Boot 项目来调用该模型…

Java 大视界 -- 基于 Java 的大数据分布式缓存一致性维护策略解析(109)

&#x1f496;亲爱的朋友们&#xff0c;热烈欢迎来到 青云交的博客&#xff01;能与诸位在此相逢&#xff0c;我倍感荣幸。在这飞速更迭的时代&#xff0c;我们都渴望一方心灵净土&#xff0c;而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识&#xff0c;也…

ansible自动化运维工具学习笔记

目录 ansible环境部署 控制端准备 被控制端准备 ansible批量管理主机的方式主要有两种 配置准备&#xff1a; ssh密码认证方式管理机器 密码登录&#xff0c;需要各主机密码相同 配置免密登录 ssh密钥方式批量管理主机 ansible实现批量化主机管理的模式 ansible-doc命令 comman…

2025-02-27 学习记录--C/C++-PTA 7-29 删除字符串中的子串

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h> // 引入标准输入输出库&#xff0c…

ETL-kettle数据转换使用详解

一、excel转换成mysql 表格就按照我们刚才转换的表格来转换成MySQL数据 在MySQL数据库中创建数据库&#xff0c;这个根据自身情况。我就在现有test库中测试了。 根据以上步骤&#xff0c;新建转换。 构建流程图&#xff0c;选择excel输入和表输出 将两个组件连接起来 双击…

AI人工智能机器学习之聚类分析

1、概要 本篇学习AI人工智能机器学习之聚类分析&#xff0c;以KMeans、AgglomerativeClustering、DBSCAN为例&#xff0c;从代码层面讲述机器学习中的聚类分析。 2、聚类分析 - 简介 聚类分析是一种无监督学习的方法&#xff0c;用于将数据集中的样本划分为不同的组&#xff…

MybatisPlus详细使用

文章目录 一、Mybatis Plus的使用步骤二、常见注解三、常见配置四、核心功能4.1、条件构造器4.2、自定义sql4.3、Service接口 五、LambdaQueryWrapper常用方法详解 一、Mybatis Plus的使用步骤 1、引入MybatisPlus的起步依赖 MyBatisPlus官方提供了starter&#xff0c;其中集成…

Spring项目-抽奖系统(实操项目-用户管理接口)(END)

^__^ (oo)\______ (__)\ )\/\ ||----w | || || 一&#xff1a;前言&#xff1a; 活动创建及展示博客链接&#xff1a;Spring项目-抽奖系统(实操项目-用户管理接口)(THREE)-CSDN博客 上一次完成了活动的创建和活动的展示&#xff0c;接下来就是重头戏—…

宝塔webhooks与码云实现自动部署

1. 宝塔面板配置Webhook 登录宝塔面板&#xff0c;进入「软件商店」→ 搜索「Webhook」并安装。添加Webhook&#xff1a; 名称&#xff1a;自定义&#xff08;如 Gitee自动部署&#xff09;脚本&#xff1a;编写部署脚本&#xff0c;示例如下&#xff1a;#!/bin/bash# 项目路径…

springboot之集成Elasticsearch

目录 二、Elasticsearch 是什么&#xff1f;三、Elasticsearch 安装四、Springboot 集成 Elasticsearch 的方式五、创建项目集成 Elasticsearch 2.创建 Spring Initializr 项目 es &#xff08;3&#xff09;.新建实体类 User&#xff08;4&#xff09;.新建 dao 接口类 UserR…