4.23学习总结

news2025/1/12 18:16:43

一.NIO(一)

(一).简介:

NIO 是 Java SE 1.4 引入的一组新的 I/O 相关的 API,它提供了非阻塞式 I/O、选择器、通道、缓冲区等新的概念和机制。相比与传统的 I/O 多出的 N 不是单纯的 New,更多的是代表了 Non-blocking 非阻塞,NIO具有更高的并发性、可扩展性以及更少的资源消耗等优点。

(二).NIO 与传统BIO:

NIO:是同步非阻塞的,服务器实现模式为 一个线程处理多个连接。服务端只会创建一个线程负责管理Selector(多路复用器),Selector(多路复用器)不断的轮询注册其上的Channel(通道)中的 I/O 事件,并将监听到的事件进行相应的处理。每个客户端与服务端建立连接时会创建一个 SocketChannel 通道,通过 SocketChannel 进行数据交互。

BIO:全称是Blocking IO,同步阻塞式IO,是JDK1.4之前的传统IO模型,服务器实现模式为一个连接一个线程。每当客户端有连接请求时服务器端就需要启动一个线程进行处理。

两者主要区别如下:

  • 阻塞和非阻塞:NIO 使用非阻塞式 I/O,而 BIO 使用阻塞式 I/O。在阻塞式 I/O 中,当一个 I/O 操作完成之前,线程会一直被阻塞,直到 I/O 操作完成;在非阻塞式 I/O 中,线程可以继续执行其他任务,直到 I/O 操作完成并返回结果。
  • 线程模型:NIO 中的线程模型是基于事件驱动的,当一个 I/O 操作完成时,会触发相应的事件通知线程处理;而在 BIO 中,每个线程都负责处理一个客户端连接,需要不断地轮询客户端的输入输出流,以便及时响应客户端的请求。
  • 内存消耗:NIO 中使用的缓冲区(Buffer)可以重复利用,减少了频繁的内存分配和回收,从而减少了内存的消耗;而在 BIO 中,每个客户端连接都需要单独分配一个缓冲区,容易造成内存的浪费。
  • 并发性能:NIO 中使用非阻塞式 I/O,可以同时处理多个客户端连接,从而提高了并发处理能力;而在 BIO 中,由于每个客户端连接都需要一个线程来处理,当连接数量增加时,容易出现线程饥饿和资源耗尽的问题。

 

(三).NIO的核心原理

 

 工作流程:

  • 创建 Selector:Selector 是 NIO 的核心组件之一,它可以同时监听多个通道上的 I/O 事件,并且可以通过 select() 方法等待事件的发生。
  • 注册 Channel:通过 Channel 的 register() 方法将 Channel 注册到 Selector 上,这样 Selector 就可以监听 Channel 上的 I/O 事件。
  • 等待事件:调用 Selector 的 select() 方法等待事件的发生,当有事件发生时,Selector 就会通知相应的线程进行处理。
  • 处理事件:根据不同的事件类型,调用对应的处理逻辑。
  • 关闭 Channel:当 Channel 不再需要使用时,需要调用 Channel 的 close() 方法关闭 Channel,同时也需要调用 Buffer 的 clear() 方法清空 Buffer 中的数据,以释放内存资源。

 

 二.java聊天室控制台实现公聊私聊

其私聊核心思路就是hashmap将每个人的id(用户名)和其对应的输出流,形成键值对,存到hashmap中,在需要的时候,直接根据用户名就可以调出其对应的输出流.

公聊的核心思路在于使用ArrayList集合,将所有用户的输出流都存入集合中,然后遍历对每个用户进行输出.

实例代码:

客户端:

public class Client {
    public static void main(String[] args) {
        //连接服务器
        try {
            System.out.println("连接服务端");
            Socket socket = new Socket("localhost",8088);
            System.out.println("连接服务端成功");
            Thread t1 = new Thread(new ClientWriteData(socket));
            Thread t2 = new Thread(new ClientReadData(socket));
            t1.start();
            t2.start();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ClientWriteData implements Runnable{
    private Scanner scan;
    private Socket socket;
    public ClientWriteData(Socket socket){
        this.socket = socket;
    }
    public void run(){
        try {
            OutputStream out = socket.getOutputStream();
            OutputStreamWriter osw;osw = new OutputStreamWriter(out,"GBK");
            PrintWriter pw = new PrintWriter(osw,true);
            System.out.println("请输入用户名:");
            scan = new Scanner(System.in);
            String str0 = scan.next();
            pw.println(str0);
            while(true){
                System.out.println("请选择私聊或者群发:1表示私聊\t2表示群发");
                int n = scan.nextInt();
                pw.println(n);
                switch(n){
                    case 1:
                        System.out.println("请输入私聊对象: ");
                        String name = scan.next();
                        pw.println(name);
                        System.out.println("私聊的信息:");
                        String str = scan.next();
                        pw.println(str);
                        break;
                    case 2:
                        System.out.println("请输入群发消息:");
                        System.out.println(str0+"正在发消息:");
                        String str1 = scan.next();
                        pw.println(str1);
                        break;
                    default:
                        System.out.println("退出消息发送:");
                        System.exit(0);
                }

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
class ClientReadData implements Runnable{
    private Socket socket;
    public ClientReadData(Socket socket){
        this.socket = socket;
    }
    public void run(){
        try {
            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is,"GBK");
            BufferedReader br = new BufferedReader(isr);
            String str = null;
            while((str = br.readLine())!=null){
                System.out.println(str);
            }
        } catch (IOException e) {
            System.err.println("服务端已断开!!!");
            e.printStackTrace();
        }
    }
}

服务端:

public class Server {
    //群发
    //定义一个集合,用于存储所有客户端的输出流
    List<PrintWriter> allPw = new ArrayList<>();
    //用于根据用户名存储客户端输出流
    Map<String,PrintWriter> map = new HashMap();
    //创建线程池对象
    //ExecutorService pool = Executors.newCachedThreadPool();
    public static void main(String[] args) {
        try {
            //向系统申请端口号 端口号是系统中所有程序没有使用过的端口,才能使用成功
            //端口号的范围:0-65535之间 0-1023之间是系统端口
            ServerSocket server = new ServerSocket(8088);
            System.out.println("服务端开启成功!!!");
            Server s = new Server();
            while(true){
                System.out.println("等待客户端连接:");
                //阻塞方法 accept():等待客户端的连接
                Socket accept = server.accept();
                System.out.println("和客户端连接成功!!!");
                //获取IP地址
                InetAddress address = accept.getInetAddress();
                String ip = address.getHostAddress();
                System.out.println(ip);
                Thread t = new Thread(s.new ClientHandler(accept));
                t.start();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    class ClientHandler implements Runnable{
        private Socket socket;
        public ClientHandler(Socket socket){
            this.socket = socket;
        }
        public void run(){
            try{
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is,"GBK");
                BufferedReader br = new BufferedReader(isr);

                OutputStream os = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os,"GBK");
                PrintWriter pw = new PrintWriter(osw,true);
                //一个客户端连接服务器,则把输出流存入到集合中
                String str = null;
                //用户名
                String name = br.readLine();
                allPw.add(pw);
                map.put(name, pw);
                while((str = br.readLine())!=null){
                    if(str.equals("1")){//私聊工作
                        //需要私聊的对象
                        str = br.readLine();
                        //私聊对象的输出流
                        PrintWriter p = map.get(str);
                        str = br.readLine();
                        p.println(str);
                    }else{//群发

                        System.out.println("");
                        str = br.readLine();
                        for(PrintWriter p:allPw){
                            if(p == pw){
                                continue;
                            }
                            p.println(str);
                        }
                    }
                }
            }catch(IOException e){
                e.printStackTrace();
            }
        }
    }
}

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

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

相关文章

ABeam×StartUp丨蓝因机器人访问ABeam旗下德硕管理咨询(深圳)新创部门,展开合作交流

近日&#xff0c;深圳蓝因机器人科技有限公司&#xff08;以下简称“蓝因机器人”&#xff09;创始人陈卜铭先生来访ABeam旗下德硕管理咨询&#xff08;深圳&#xff09;有限公司&#xff08;以下简称“ABeam-SZ”&#xff09;&#xff0c;与新创部门展开合作交流。 交流中&am…

测试 mybatis 是否生效【具有增删改查的功能】

一、 1.1按 anl enter 1.2 注意点&#xff1a; test 下 与 上面的名字需保持一致 测试上面的&#xff0c;路径需保持一致&#xff0c;不一致&#xff0c;后期可能会报错。不是相同目录可能会找不到启动类 1.3 写测试 1.4.1 【先】 添加插件 【一键调用一个对象的所有的se…

C++类和对象:赋值重载,const成员,取地址及const取地址操作符重载

文章目录 1.赋值运算符重载1.1运算符重载1.2 赋值运算符重载1.3 前置和后置重载 2.日期类的实现3. const成员函数4 取地址及const取地址操作符重载 上文介绍了前三个默认成员函数&#xff0c;本文会介绍剩下三个&#xff0c; 赋值重载会重点展开。 1.赋值运算符重载 1.1运算符…

双非一战逆天改命,上岸Top3!

这个系列会邀请上岸学长学姐进行经验分享~今天经验分享的同学同样是小马哥上海交大819的全程班学员&#xff0c;双非逆袭上岸&#xff0c;非常厉害&#xff01; 01-前言 个人介绍&#xff1a;本人就读于江苏某双非&#xff0c;绩点3.2&#xff0c;本科期间仅校赛级别奖项。四…

JavaSE内部类

内部类概述 1.内部类的基础 内部类的分类&#xff1a;实例化内部类&#xff0c;静态内部类&#xff0c;局部内部类和匿名内部类 public class OutClass {// 成员位置定义&#xff1a;未被static修饰 --->实例内部类public class InnerClass1{}// 成员位置定义&#xff1a;被…

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南

公园景区伴随音乐系统-公园景区数字IP广播伴随音乐系统建设指南 由北京海特伟业任洪卓发布于2024年4月23日 随着“互联网”被提升为国家战略&#xff0c;传统行业与互联网的深度融合正在如火如荼地展开。在这一大背景下&#xff0c;海特伟业紧跟时代步伐&#xff0c;凭借其深厚…

如何在PostgreSQL中跟踪和分析查询日志,以便于排查性能瓶颈?

文章目录 启用查询日志分析查询日志1. 查找执行时间长的查询2. 分析资源消耗3. 使用pgBadger分析4. 优化查询 示例代码结论 在PostgreSQL中&#xff0c;跟踪和分析查询日志是排查性能瓶颈的重要步骤。通过查看和分析查询日志&#xff0c;我们可以了解哪些查询在执行时遇到了问题…

17.Nacos与Eureka区别

Nacos会将服务的提供者分为临时实例和非临时实例。默认为临时实例。 临时实例跟eureka一样&#xff0c;会向注册中心报告心跳监测自己是否还活着。如果不正常了nacos会剔除临时实例。&#xff08;捡来的孩子&#xff09; 非临时实例&#xff0c;nacos会主动询问服务提供者是否…

232 基于matlab的MIMO雷达模型下一种子空间谱估计方法

基于matlab的MIMO雷达模型下一种子空间谱估计方法&#xff0c;采用过估计的方法&#xff0c;避免了信源数估计的问题&#xff0c;对数据协方差矩阵进行变换&#xff0c;构造信号子空间投影矩阵和噪声子空间投影矩阵&#xff0c;不需要像经典的MUSIC一样对其进行特征分解&#x…

BBS前后端混合项目--03

展示 static/bootstrp # bootstrap.min.css /*!* Bootstrap v3.4.1 (https://getbootstrap.com/)* Copyright 2011-2019 Twitter, Inc.* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)*//*! normalize.css v3.0.3 | MIT License | github.com/n…

Python练习03

题目 解题思路 Demo58 通过字符串切片来进行反转操作 def _reverse():"""这是一个反转整数的函数"""num input("请输入想要反转的整数")print(num[::-1]) 运行结果 Demo61 首先制作一个判断边长的函数&#xff0c;通过三角形两边…

vue3项目 使用 element-plus 中 el-collapse 折叠面板

最近接触拉了一个项目&#xff0c;使用到 element-plus 中 el-collapse 折叠面板&#xff0c;发现在使用中利用高官网多多少少的会出现问题。 &#xff08;1.直接默认一个展开值&#xff0c;发现时显时不显 2 . 数据渲染问题&#xff0c;接口请求了&#xff0c;页面数据不更新 …

捕捉信号的处理

文章目录 信号捕捉 信号捕捉 信号捕捉是进程从内核态返回用户态时会对信号进行检测处理。 如果信号的处理动作是用户自定义函数,在信号递达时就调用这个函数,这称为捕捉信号。由于信号处理函数的代码是在用户空间的,处理过程比较复杂,举例如下: 用户程序注册了SIGQUIT信号的处…

linux——cron定时任务

cron定时任务配置文件中可以查看一些信息 crontab就是在提交以及管理需要周期性执行的任务 定时任务具体实现需要使用crontab命令编辑对应定时任务文件 这里执行定时任务&#xff0c;每分钟创建一个文件1.txt

jvm中的垃圾回收器

Jvm中的垃圾回收器 在jvm中&#xff0c;实现了多种垃圾收集器&#xff0c; 包括&#xff1a; 1.串行垃圾收集器 2.并行垃圾收集器 3.CMS&#xff08;并发&#xff09;垃圾收集器 4.G1垃圾收集器 1.串行垃圾回收器 效率低&#xff0c;使用较少 2.并行垃圾回收器 3.并发垃圾回…

mysql download 2024

好久没在官网下载 mysql server 安装包。今天想下载发现&#xff1a; 我访问mysql官网的速度好慢啊。mysql server 的下载页面在哪里啊&#xff0c;一下两下找不到。 最后&#xff0c;慢慢悠悠终于找到了下载页面&#xff0c;如下&#xff1a; https://dev.mysql.com/downlo…

3 命名实体识别调优化

能走到这里说明你对模型微调有了一个基本的认识。那么开始一段命名实体的任务过程&#xff0c;下面使用huggingface官网的数据。 1 准备模型 下面的模型自己选择一个吧&#xff0c;我的内存太第一个模型跑不了。 https://huggingface.co/ckiplab/bert-base-chinese-ner/tree…

医学访问学者专栏—研究领域及工作内容

在国外访问学者申请中&#xff0c;医学领域的研究、教学及从业人员占有相当大的比例&#xff0c;这些医学访问学者的研究领域及工作内容都有哪些&#xff1f;本文知识人网小编就相关问题进行详细阐述&#xff0c;并附带案例说明。 一、在国外做医学访问学者可以从事哪些工作&am…

Win10 打开有些软件主界面会白屏不显示,其他软件都正常

环境&#xff1a; Win10专业版 英伟达4070 显卡 问题描述&#xff1a; Win10 打开有些软件主界面会白屏不显示,打开远程协助软件AIRMdesk,白色&#xff0c;其他软件都正常 解决方案&#xff1a; 网上说电脑没有接显示器独立显卡的关系导致 我是只有一台主机&#xff0c;没…

appium相关的知识

>adb shell dumpsys window | findstr mCurrentFocus adb devices # 实例化字典 desired_caps = dict() desired_caps[platformName] = Android desired_caps[platformVersion] = 9 # devices desired_caps[deviceName] = emulator-5554 # 包名 desired_caps[appPackage] …