广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java 中的io模型详解
  • 291
分享到

Java 中的io模型详解

JavaioJavaio模型 2022-11-12 00:11:26 291人浏览 泡泡鱼

Python 官方文档:入门教程 => 点击学习

摘要

目录1. Bio2. NIO3. 多路复用最后再说几个小问题1. BIO 我们先看一个 Java 例子: package cn.bridgeli.demo;   imp

1. BIO

我们先看一个 Java 例子:


package cn.bridgeli.demo;
 
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
 

public class SocketBIO {
 
 
    public static void main(String[] args) throws Exception {
        ServerSocket server = new ServerSocket(9090, 20);
 
        System.out.println("step1: new ServerSocket(9090) ");
 
        while (true) {
            Socket client = server.accept();
            System.out.println("step2:client: " + client.getPort());
 
            new Thread(new Runnable() {
                @Override
                public void run() {
                    InputStream inputStream = null;
                    BufferedReader reader = null;
                    try {
                        inputStream = client.getInputStream();
                        reader = new BufferedReader(new InputStreamReader(inputStream));
                        while (true) {
                            String dataLine = reader.readLine(); //阻塞2
                            if (null != dataLine) {
                                System.out.println(dataLine);
                            } else {
                                client.close();
                                break;
                            }
                        }
                        System.out.println("客户端断开");
                    } catch (IOException e) {
                        e.printStackTrace();
                    } finally {
                        if (null != reader) {
                            try {
                                reader.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                        if (null!= inputStream) {
                            try {
                                inputStream.close();
                            } catch (IOException e) {
                                e.printStackTrace();
                            }
                        }
                    }
 
                }
 
 
            }).start();
 
        }
    }
 
}

BIO 是最初始的 IO 模型,该模型有两个大问题:1. accept 是阻塞的;2. read 也是阻塞的,也就是说我们的服务器起来之后,首先会在 accept 处阻塞,等待客户端连接,但有一个客户端连接的时候,我们可以从客户端处读取数据,这个时候也是阻塞的,所以我们的系统只能是单连接的,当有多个客户端连接的时候,只能一个一个的排着队连接,然后从客户端中读取数据,为了实现多连接,这就要求我们必须启用线程来解决,最开始等待客户端连接,然后有一个客户端连上了之后,启动一个线程读取客户端的数据,然后主线程继续等待客户端连接。

该模型最大的问题就是缺乏弹性伸缩能力,当客户端并发访问量增加后,服务端的线程个数和客户端并发访问数呈1:1的正比关系,Java 中的线程也是比较宝贵的系统资源,线程数量快速膨胀后,系统的性能将急剧下降,随着访问量的继续增大,系统最终就死掉了。当然不仅仅是 Java,我们直接设想假设有一万个客户端连接到服务端,服务端要开一万个线程,那么这个时候服务端光开线程要占用多少资源?需要多大内存?操作系统为了调度这些线程 CPU 是不是也要被占用完了?

为了解决此问题,有人对服务器的线程模型进行优化,服务端采用线程池来处理多个客户端请求。但是同样是有问题的,

1. 线程总数有限,又要等待;

2. 多余的连接会堆积在任务队列中,当任务队列满了,那么此时就开始启用拒绝策略了,所以还是没有从根本上解决问题。

2. NIO

BIO 最大的问题,在于 B,block,阻塞,所以只要解决了这个问题就可以,那么此时 NIO 应运而生,N 就是 non-block 的意思(Java 中是 new 的意思),同样先看一个例子:


package cn.bridgeli.demo;
 
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;
 

public class SocketNIO {
 
    public static void main(String[] args) throws Exception {
 
        LinkedList<SocketChannel> clients = new LinkedList<>();
 
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.bind(new InetSocketAddress(9090));
        serverSocketChannel.configureBlocking(false);
 
        while (true) {
            SocketChannel client = serverSocketChannel.accept();
 
            if (null != client) {
                client.configureBlocking(false);
                System.out.println("client port: " + client.socket().getPort());
                clients.add(client);
            }
 
            ByteBuffer buffer = ByteBuffer.allocateDirect(4096);
 
            for (SocketChannel c : clients) {
                int num = c.read(buffer);
                if (num > 0) {
                    buffer.flip();
                    byte[] aaa = new byte[buffer.limit()];
                    buffer.get(aaa);
 
                    String b = new String(aaa);
                    System.out.println(c.socket().getPort() + " : " + b);
                    buffer.clear();
                }
            }
        }
    }
 
}

这个时候我们会发现连接和读取都是非阻塞的了,由于都是非阻塞的,所以这就要求我们需要有一个集合,用来存储所有的连接,然后从连接中读取数据。这个模型解决了我们需要开线程的问题,没循环一次,如果有新连接过来,我们就把连接放到集合中,然后挨个读取连接中的数据,此时就不需要我们每连接每线程了,但是还是有一个问题,随着连接的增加,我们的队列会越来越大,而且我们每次都要遍历所有的连接读取数据,我们还假设有一万个连接,但是前 9999 个连接都没有数据,只有最后一个连接有数据,那前 9999 次读取都是浪费。

3. 多路复用

为了解决 NIO 中无效读取的问题,这个时候我们可以根据事件监听,告诉操作系统说,我们监听那些事件,然后当这些事件有数据到达时通知我们去读取,例子如下:


package cn.bridgeli.demo;
 
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;
 

public class SocketMultiplexingIO {
 
    private ServerSocketChannel serverSocketChannel = null;
    private Selector selector = null;
 
    public void initServer() {
        try {
            serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.configureBlocking(false);
            serverSocketChannel.bind(new InetSocketAddress(9090));
            selector = Selector.open();
            serverSocketChannel.reGISter(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    public void start() {
        initServer();
        System.out.println("服务器启动了...");
        try {
            while (true) {
 
                while (selector.select() > 0) {
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> iterator = selectionKeys.iterator();
                    while (iterator.hasNext()) {
                        SelectionKey key = iterator.next();
                        iterator.remove();
                        if (key.isAcceptable()) {
                            acceptHandler(key);
                        } else if (key.isReadable()) {
                            readHandler(key);
                        }
                    }
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    public void acceptHandler(SelectionKey key) {
        try {
            ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
            SocketChannel client = ssc.accept();
            client.configureBlocking(false);
 
            ByteBuffer buffer = ByteBuffer.allocate(8192);
 
            client.register(selector, SelectionKey.OP_READ, buffer);
            System.out.println("新客户端:" + client.getRemoteAddress());
 
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
 
    public void readHandler(SelectionKey key) {
        SocketChannel client = (SocketChannel) key.channel();
        ByteBuffer buffer = (ByteBuffer) key.attachment();
        buffer.clear();
        int read = 0;
        try {
            while (true) {
                read = client.read(buffer);
                if (read > 0) {
                    buffer.flip();
                    while (buffer.hasRemaining()) {
                        client.write(buffer);
                    }
                    buffer.clear();
                } else if (read == 0) {
                    break;
                } else {
                    client.close();
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
 
        }
    }
 
    public static void main(String[] args) {
        SocketMultiplexingIO service = new SocketMultiplexingIO();
        service.start();
    }
}

再多路复用中,有 poll、epoll、Selector 等实现方式,其中他们的区别是,poll 需要我们每次告诉操作系统说,我们都要关注哪些事件,而 epoll 是操作系统会开辟一块内存区域,存储下我们要关注的事件,不用每次都告诉操作系统我们关注哪些事件。

关于 BIO、NIO、多路复用,马士兵教育的周志磊老师有一个很形象的例子。BIO 是阻塞的,所以需要我们每连接每线程,就相当于我们为每一辆车在收费站修建一条路,每来一辆车就要修一条路,我们我们自己从车上卸下装的货;NIO 是非阻塞的,我们就需要我们每次都跑到收费站,然后看我们修好的路上面车来了没有,没有来的话,等下次在看,来的话,我们卸下货,再等下次看有没有新货;多路复用中的 poll,就是我们在收费站安装一个电话机,然后我们每次打电话,我关注的哪些路是否有车来了,需要我卸货,而 epoll 是我们不仅在收费站安装了一个电话机,我们还留下了一个本子,我们每次打电话的时候,会把我们新关注的路告诉收费站,收费站在本子上记下我们关注的那些路,假设我们关注一万条路,这样就不需要我们每次在电话中每次把这一万条路说一边,问这些路是否有车来了,需要我们卸货。

最后再说几个小问题

1. 我们学习 IO 模型,IO 模型是操作系统提供给我们的接口,属于系统调用,所以我们可以通过 strace 追踪到每一个程序所执行的系统调用。命令如下:


strace -ff -o out + 要追踪的进程

2. 当我们追踪 BIO 的时候,因为 jdk 的优化,所以如果使用高版本的 JDK,也不会看到阻塞,这个时候你可以通过 JDK1.4 编译运行(这也是为什么我们使用 lambda 表达式和 try-with-resource 的原因)

3. IO 调用属于系统调用,所以从 BIO -> NIO -> 多路复用,是操作系统的进步,而我们各种变成语言写的属于应用,所以有没有 异步非阻塞IO 模型,这样看操作系统底层有没有这样的模型,需要操作系统给我们提供 异步非阻塞IO 相关的接口,我们的应用才能进一步优化

4. 我们通过 strace 追踪到的每一个系统调用,都可以通过 man 命令查看文档(仅限 linux 系统,非 windows 系统),如果没有 man 命令,安装一下就可以了。

以上就是Java 中的io模型详解的详细内容,更多关于Java io模型的资料请关注编程网其它相关文章!

--结束END--

本文标题: Java 中的io模型详解

本文链接: https://www.lsjlt.com/news/122706.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java 中的io模型详解
    目录1. BIO2. NIO3. 多路复用最后再说几个小问题1. BIO 我们先看一个 Java 例子: package cn.bridgeli.demo;   imp...
    99+
    2022-11-12
    Java io Java io模型
  • Linux的5种IO模型用法详解
    目录阻塞IO(blocking I/O)非阻塞IO(Non-Blocking I/O)多路复用IO(I/O Multiplexing)信号驱动式IO(Signal-Driven I/O)异步IO(Asynchronous...
    99+
    2023-05-12
    Linux 5种IO模型 Linux IO模型 Linux IO
  • 常见JAVA中IO/NIO模型
    我们常见的IO模型有:阻塞 IO 模型、非阻塞 IO 模型、多路复用 IO 模型、 信号驱动 IO 模型、异步 IO 模型;下面我们就简单介绍一下以上IO模型。1、阻塞 IO 模型最传统的一种IO 模型,即在读写数据过程中会发生阻塞现象。当...
    99+
    2018-06-10
    java教程 JAVA
  • 详解Java中的原型模式
    本篇文章为大家展示了详解Java中的原型模式,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。类型:创建类模式类图:原型模式主要用于对...
    99+
    2023-05-31
    java 原型模式 ava
  • Java IO网络模型实现解析
    目录前言正文一. BIO二. Non Blocking IO三. IO多路复用四. NIO总结前言 本篇文章会对Java中的网络IO模型的概念进行解释,并给出具体的Java代码实现...
    99+
    2023-03-19
    Java IO网络模型 Java IO
  • 一文让你了解透彻Java中的IO模型
    目录什么是IO常见的IO模型BIO(Blocking IO)如何优化NIO的面世NIO(Non-blocking/New IO)同步非阻塞IO模型IO多路复用模型Java中的NIOA...
    99+
    2023-05-18
    Java IO模型 Java IO
  • Java IO模型与Java网络编程模型的对比
    本篇内容主要讲解“Java IO模型与Java网络编程模型的对比”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java IO模型与Java网络编程模型的对比”吧!IO模型介绍作者:cooffee...
    99+
    2023-06-02
  • Java IO详解
    一、I/O简介 IO即Input和Output,即输入和输出。这里的输入和输出都是相对于内存来说的,具体见下图。 InputStream/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流。 OutputStream/Wr...
    99+
    2023-08-20
    java
  • 深入浅析Java NIO中的IO模型
    这期内容当中小编将会给大家带来有关深入浅析Java NIO中的IO模型,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。一.什么是同步?什么是异步  同步和异步的概念出来已经很久了,网上有关同步和异步的说法也...
    99+
    2023-05-31
    java io模型 nio
  • Python的io模块详解
    Python的io模块提供了多个流式处理接口,具体的处理函数实现位于_pyio.py模块中。 在_io.py模块中,提供了唯一的模块方法open(name, mode=None, buffering=None),但是没有read()方法。...
    99+
    2023-01-31
    详解 模块 Python
  • 详解Java的内存模型
    目录JVM的内存模型Java “一次运行,到处编译” 的真面目JVM的本质和位置JVM的内存模型总览线程私有区域线程共享区域直接内存从例子来理解内存模型JVM的内存模型 Java “...
    99+
    2022-11-12
    Java 内存模型
  • c++中的基本IO类型详解
    引言 c++不直接处理输入和输出,而是通过标准库中的类型处理IO。IO的设备可以是文件、控制台、string。c++主要定义了三种IO类型,分别被包含在iostream、fstrea...
    99+
    2022-11-12
    c++ io类型 c++ io
  • Java内存模型详解
    目录什么是JMM主存与工作内存volatile 关键字有什么用一个线程对共享变量做了修改之后,其他的线程能够看到(感知到)该变量的这种修改(变化)什么是JMM JMM全称Java M...
    99+
    2023-05-18
    Java内存模型 Java JMM模型
  • Java——内存模型详解!
    Java内存模型是一种抽象的规则或规范,定义了程序中存在竞争现象的对象(包括实例字段、静态字段和数组对象,不包括局部变量,形式参数;后者是线程私有,不存在竞争问题)的访问方式。         如果我们要想深入了解Java并发编程,就要先理...
    99+
    2023-10-20
    java 开发语言
  • Java io流 详解
    文章目录 前言一、IO流的分类二、流的原理及流的数量三、Java IO流对象1. 输入字节流InputStream2. 输出字节流OutputStream 前言 "IO流"(Inpu...
    99+
    2023-09-17
    java 开发语言
  • JAVA—IO流详解
    1. 流概述 1.1. 什么是IO IO:Input/Output即输入&输出,也称之为流(河流,水流),指的是数据从一个地点到另一个地点过程;对于计算机来说文件的拷贝过程,文件的编写保存,显示功能都是使用到IO;将数据的传输过程看做一个输...
    99+
    2023-08-16
    java jvm 网络
  • Java 基础详解(泛型、集合、IO、反射)
    计划把 Java 基础的有些部分再次看一遍,巩固一下,下面以及以后就会分享自己再次学习的一点笔记!不是有关标题的所有知识点,只是自己觉得模糊的一些知识点。1.对于泛型类而言,你若没有指明其类型,默认为Object;2.在继承泛型类以及接口的...
    99+
    2023-05-30
    java 泛型 集合
  • Java结构型模式中的组合模式详解
    目录一.介绍二.UML类图1.透明方式2.安全方式三.具体代码四.使用场景五.优点一.介绍 组合模式(Composite Pattern)属于结构型模式。组合模式又叫作部分整体模式,...
    99+
    2023-02-16
    Java结构型模式 Java组合模式
  • Java IO模型中的BIO,NIO和AIO是什么
    本篇内容主要讲解“Java IO模型中的BIO,NIO和AIO是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java IO模型中的BIO,NIO和AIO是什么”吧!一、I/O模型1.1 I...
    99+
    2023-06-29
  • Java内存模型JMM详解
    Java Memory Model简称JMM, 是一系列的Java虚拟机平台对开发者提供的多线程环境下的内存可见性、是否可以重排序等问题的无关具体平台的统一的保证。(可能在术语上与Java运行时内存分布有歧义,后者指堆、方法区、线程栈等内存...
    99+
    2023-05-30
    java 内存模型 详解
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作