【谈谈IO】BIO、NIO和AIO

BIO:

  BIO是阻塞IO,体现在一个线程调用IO的时候,会挂起等待,然后Thread会进入blocked状态;这样线程资源就会被闲置,造成资源浪费,通常一个系统线程数是有限的,而且,Thread进入内核态也是很大的性能开销。而阻塞方式,意味着BIO必然是一个同步IO。

  BIO还有一个显著的特点是面向流式Stream编程,特点是实现简单,但也意味着拓展性差。

 

NIO:

  NIO,通常实现为同步非阻塞IO,同步意味着不会产生会调,需要线程自身去同步IO是否完成,而非阻塞就是线程会立刻返回。

  相对于BIO面向流式抽象思想编程,NIO是面向管道编程的,例如在Java中必谈的三个封装类Buffer、Channel、Sellector,就是管道编程的体现,Java1.4后提供的非阻塞 IO 的核心在于使用一个 Selector 来管理多个通道,可以是 SocketChannel,也可以是 ServerSocketChannel,将各个通道注册到 Selector 上,指定监听的事件。之后可以只用一个线程来轮询这个 Selector,看看上面是否有通道是准备好的,当通道准备好可读或可写,然后才去开始真正的读写,这样速度就很快了。我们就完全没有必要给每个通道都起一个线程。如下面代码所示:

 1 package com.mobisummer.spider.slave.task.aliexpress.region;
 2 
 3 import java.io.IOException;
 4 import java.net.InetSocketAddress;
 5 import java.net.ServerSocket;
 6 import java.nio.ByteBuffer;
 7 import java.nio.channels.SelectionKey;
 8 import java.nio.channels.Selector;
 9 import java.nio.channels.ServerSocketChannel;
10 import java.nio.channels.SocketChannel;
11 import java.util.Iterator;
12 import java.util.Set;
13 
14 public class PlainNioServer {
15 
16   public void serve(int port) throws IOException {
17 
18     ServerSocketChannel serverChannel = ServerSocketChannel.open();
19     serverChannel.configureBlocking(false);
20     ServerSocket ssocket = serverChannel.socket();
21     InetSocketAddress address = new InetSocketAddress(port);
22     ssocket.bind(address);
23     Selector selector = Selector.open();
24     serverChannel.register(selector, SelectionKey.OP_ACCEPT);
25     final ByteBuffer msg = ByteBuffer.wrap("Hi!\r\n".getBytes());
26 
27     for (; ; ) {
28       try {
29         selector.select();
30       } catch (IOException ex) {
31         ex.printStackTrace();
32         // handle exception
33         break;
34       }
35       Set<SelectionKey> readyKeys = selector.selectedKeys();
36       Iterator<SelectionKey> iterator = readyKeys.iterator();
37       while (iterator.hasNext()) {
38         SelectionKey key = iterator.next();
39         iterator.remove();
40         try {
41           if (key.isAcceptable()) {
42             ServerSocketChannel server = (ServerSocketChannel) key.channel();
43             SocketChannel client = server.accept();
44             client.configureBlocking(false);
45             client.register(selector,
46                             SelectionKey.OP_WRITE | SelectionKey.OP_READ,
47                             msg.duplicate());
48             System.out.println("Accepted connection from " + client);
49           }
50           if (key.isWritable()) {
51             SocketChannel client = (SocketChannel) key.channel();
52             ByteBuffer buffer = (ByteBuffer) key.attachment();
53             while (buffer.hasRemaining()) {
54               if (client.write(buffer) == 0) {
55                 break;
56               }
57             }
58             client.close();
59           }
60         } catch (IOException ex) {
61           key.cancel();
62           try {
63             key.channel().close();
64           } catch (IOException cex) {
65             // ignore on close
66           }
67         }
68       }
69     }
70   }
71 }

 

  对于并发数量大但处理的任务又十分快速的时候用处十分显著,代替了之前的利用多线程解决业务问题的方案,就是利用单线程以及底层epoll或者poll原理完成了单线程处理多任务的方案,理论上至少我们想到了减少线程切换的开支,而由内核去改变IO状态。

  【说说实现】

  NIO 中 Selector 是对底层操作系统实现的一个抽象,管理通道状态其实都是底层系统实现的,在不同系统下的实现会不同,是自动选择的,可能的实现方式如下:

  select:上世纪 80 年代的事情了,它支持注册 FD_SETSIZE(1024) 个 socket,在那个年代肯定是够用的。

  poll:1997 年,出现了 poll 作为 select 的替代者,最大的区别就是,poll 不再限制 socket 数量。

  select 和 poll 都有一个共同的问题,那就是它们都只会告诉你有几个通道准备好了,但是不会告诉你具体是哪几个通道。所以,一旦知道有通道准备好以后,自己还是需要进行一次扫描,显然这个不太好,通道少的时候还行,一旦通道的数量是几十万个以上的时候,扫描一次的时间都很可观了,时间复杂度 O(n)。所以,后来才催生了以下实现。

  epoll:2002 年随 Linux 内核 2.5.44 发布,epoll 能直接返回具体的准备好的通道,时间复杂度 O(1)。那么这个epoll是怎么的原理呢?这就涉及操作系统的中断了,在内核的最底层是中断,类似系统回调的机制。网卡设备对应一个中断号, 当网卡收到网络端的消息的时候会向CPU发起中断请求, 然后CPU处理该请求. 通过驱动程序 进而操作系统得到通知, 系统然后通知epoll, epoll改变阻塞状态。

  除了 Linux 中的 epoll,2000 年 FreeBSD 出现了 Kqueue,还有就是,Solaris 中有 /dev/poll。

  前面说了那么多实现,但是没有出现 Windows,Windows 平台的非阻塞 IO 使用 select,我们也不必觉得 Windows 很落后,在 Windows 中 IOCP 提供的异步 IO 是比较强大的。

AIO:

  异步这个词,我想对于绝大多数开发者来说都很熟悉,很多场景下我们都会使用异步。对于我而言比较有意义的事情就是发现我所在公司自己做的底层框架Lwmf,自己做了一个声称为AIO的实现,只不过是封装了一层罢。

  通常,我们会有一个线程池用于执行异步任务,提交任务的线程将任务提交到线程池就可以立马返回,不必等到任务真正完成。如果想要知道任务的执行结果,通常是通过传递一个回调函数的方式,任务结束后去调用这个函数。

  同样的原理,Java 中的异步 IO 也是一样的,都是由一个线程池来负责执行任务,然后使用回调或自己去查询结果,所以这里涉及了两个实现方式,在Java中就是注册回调函数和使用异步任务返回的Feature实例。

  干货在这里:对象是过程的抽象,而线程是调度的抽象;所以,设计异步IO的时候,需要把线程控制的牢牢的,才能更稳健的设计哦。

  最后,不得不提一下的就是Reactor模型和Netty框架了!但不是本文重点,但这确实是java中优秀的NIO实现

 

转载于:https://www.cnblogs.com/iCanhua/p/8547133.html

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

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

相关文章

css动画-模拟正余弦曲线

今天就写一个css3抛物线的动画吧 从左到右的抛物线动画&#xff0c;我们就暂且把动作分为匀速向右运动和变速的上下运动。 水平匀速运动我们可以利用 translateX(x)&#xff1a;定义 2D 转换&#xff0c;沿着 X 轴移动元素&#xff1b;以及linear&#xff1a;动画从头到尾的速…

UVA-11549 Calculator Conundrum

InputThe first line of the input contains an integer t (1 ≤ t ≤ 200), the number of test cases. Each test casecontains two integers n (1 ≤ n ≤ 9) and k (0 ≤ k < 10 n ) where n is the number of digits this calculatorcan display k is the starting num…

java 当前类_Java获取当前类名的两种方法

适用于非静态方法&#xff1a;this.getClass().getName()适用于静态方法&#xff1a;Thread.currentThread().getStackTrace()[1].getClassName()获取类名&#xff1a;1、在类的实例中可使用this.getClass().getName();但在static method中不能使用该方法&#xff1b;2、在stat…

具有内部类构造函数参数的Java Reflection奇数

关于Java内部类 Java允许成员类&#xff08;在其他类内定义的类&#xff09;&#xff0c;局部类&#xff08;在语句块内定义的类&#xff09;和匿名类&#xff08;无名称的类&#xff09;&#xff1a; class Outer {Object anonymous new Object(){}; // this is an anonymou…

HDOJ 1012-1020

最近感冒了&#xff0c;有点小咳嗽&#xff0c;做题速度比较慢&#xff0c;本以为这周会做的比较少&#xff0c;没想到全是水题。。。我做的也蛮开心的....对自己无语HDOJ 1012这个题目蛮简单&#xff0c;就是输出格式比较烦&#xff0c;处理好格式基本就没问题了HDOJ 1013这个…

静态页面如何实现 include 引入公用代码

一直以来&#xff0c;我司的前端都是用 php 的 include 函数来实现引入 header 、footer 这些公用代码的&#xff0c;就像下面这样&#xff1a; <!-- index.php --><!DOCTYPE html><html lang"en"><head><meta charset"UTF-8"&…

java list 循环赋值_Java List集合的坑(add方法报空指针,循环赋值时list已保存的值会改变)...

先看空指针异常&#xff1a;ListmovieInfos null;这样创建时&#xff0c;list指向为空&#xff0c;修改方法&#xff1a;ListmovieInfos new ArrayList();再看list循环赋值的问题&#xff1a;问题描述&#xff1a;for (i0;i<10;i){movieInfoSum.movieId (int)recommendatio…

ros使用时的注意事项技巧

1.rosrun package-name executable-name 比如 rosrun turtlesim turtlesim_node 2.一旦启动roscore后,便可以运行ROS程序了。ROS程序的运行实例被称为节点(node)&#xff0c;roscore叫做节点管理器 3.查看节点列表rosnode list 4.需要注意节点名并不一定与对应可执行文件名称相…

分享几道经典的javascript面试题

这几道题目还是有一点意思的&#xff0c;大家可以研究一番&#xff0c;对自己的技能提升绝对有帮助。 1、调用过程中输出的内容是什么 function fun(n, o) {console.log(o);return {fun : function(m) {return fun(m, n);}} }var a fun(0);a.fun(1);a.fun(2);a.fun(3);var…

Rete之外的生活– RIP Rete 2013 :)

我只是对我的新算法进行最后的修改。 它合并了Leaps &#xff0c; 面向集合的Match和Left / Right取消链接的概念 &#xff0c;以及我自己的一些想法。 该代码已提交&#xff0c;但我正在积累工作并编写更多测试。 我将在一周左右的时间内写一个完整的博客&#xff0c;详细介绍…

Ubuntu+vscode打不开

前沿: vscode链接参考链接 问题: 之前在Ubuntu上安装chrome, 结果chrome没装成功, 还把vscode给qiu坏了, 貌似是当时安装chrome时提示要升级一个包. 后来发现当时是修改了libnss这个包的版本: 解决方法: # 将libnss给downgrade一下就OK了. sudo apt install libnss32:3.21-1ubu…

java线程死锁代码_java线程死锁代码示例

死锁是操作系统层面的一个错误&#xff0c;是进程死锁的简称&#xff0c;最早在 1965 年由 Dijkstra 在研究银行家算法时提出的&#xff0c;它是计算机操作系统乃至整个并发程序设计领域最难处理的问题之一。事实上&#xff0c;计算机世界有很多事情需要多线程方式去解决&#…

【2018】判定三角形

Time Limit: 3 second Memory Limit: 2 MB 输入三个正整数&#xff0c;若能用这三个数作为边长组成三角形&#xff0c;则判断三角形的形状&#xff0c;如果是等边三角形就输出“DB”&#xff0c;如果是等腰三角形就输出“DY”&#xff0c;否则就输出“YB”&#xff1b;如果不能…

纯css隐藏移动端滚动条解决方案(ios上流畅滑动)

html代码展示&#xff08;直接复制代码保存至本地文件运行即可&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, init…

Spring Data Solr教程:配置

在我的Spring Data Solr教程的上一部分中&#xff0c;我们了解到Solr提供了一个类似REST的HTTP API&#xff0c;该API可用于向Solr索引添加信息并针对索引数据执行查询。 问题在于&#xff0c;在开发环境中运行单独的Solr实例有点麻烦。 但是&#xff0c;并非所有希望都因此而…

JavaAppArguments.java

思路&#xff1a;定义一个String类型的变量&#xff0c;用来接收每次args读取到的值&#xff0c;然后把String转换为int,然后计算输出sum。 流程图&#xff1a; 源代码&#xff1a; 截图&#xff1a; 转载于:https://www.cnblogs.com/xiaohaigege666/p/7635907.html

webpack 引入jquery和第三方jquery插件

1、引入jquery jQuery 直接在 html 中引入&#xff0c;然后在 webpack 中把它配置为全局即可。 index.html: <!DOCTYPE html><html><head><meta charset"UTF-8"><title><% htmlWebpackPlugin.options.title %></title>&…

Spring Data Solr教程:CRUD(差不多)

在我的Spring Data Solr教程的上一部分中&#xff0c;我们学习了如何配置Spring Data Solr。 现在该迈出一步&#xff0c;了解我们如何管理Solr实例中存储的信息。 此博客文章描述了我们如何向Solr索引添加新文档&#xff0c;如何更新现有文档的信息以及如何从索引中删除文档。…

数独项目--关键代码展示:

关键代码展示&#xff1a; //判断该数字在当前数独是否符合要求 int judge(int num, int ple){ int x ple / 9; //x表示数字的纵坐标 int y ple % 9; //y表示数字的横坐标 int qulx x / 3; int quey y / 3; //que表示9宫格的区域 for (int i 0; i < 9; i){ if (…

java svn 版本号_eclipse中的Java文件自动根据svn版本号生成注释

经常在java代码中看到以下的注释($Rev: $Date),是不是很酷,怎么生成的呢&#xff1f;/*** A FilterChain is an object provided by the servlet container to the developer* giving a view into the invocation chain of a filtered request for a resource. Filters* use th…