IO-BIO NIO
BIO
IO:BIO:Blocking OIO:old
NIO:Non-Blocking NIO:new
BIO问题: 会创建很多的线程clone,占用很多COU资源,来回拉扯调度;
问题的根源是“阻塞”。
1.每个Socket接收到,都会创建一个线程,线程的竞争、切换上下文影响性能;
2.每个线程都会占用栈空间和CPU资源;
3.并不是每个socket都进行IO操作,无意义的线程处理;
4.客户端的并发访问增加时。服务端将呈现1:1的线程开销,访问量越大,系统将发生线程栈溢出,线程创建失败,最终导致进程宕机或者僵死,从而不能对外提供服务。
package com.wang;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 BIO {public static void main(String[] args) throws IOException {//实际上是开启了一个线程ServerSocket server = new ServerSocket(9090, 20);System.out.println("step1: new ServerSocket(9090, 20)");while (true) {Socket client = server.accept();System.out.println("step2: client\t"+client.getPort());new Thread(new Runnable() {@Overridepublic void run() {InputStream in = null;try {in = client.getInputStream();BufferedReader reader = new BufferedReader(new InputStreamReader(in));while (true){//阻塞String data = reader.readLine();if (data != null){System.out.println(data);}else {client.close();break;}}}catch (Exception e){e.printStackTrace();}}});}}
}
Linux:追踪(JDK1.4以下才能看到效果):
strace -ff -o log jdk/1.4bin/java SocketBIO
ll
trace:追踪 kernel 与 程序 的调用关系
vim xx.9837
客户端连接后,accept()就不阻塞了
clone()了一个线程之后,又重新回到accept()阻塞
查看创建的新线程文件:
新线程又开始阻塞了,等待读取数据 rev(5,
用tail -f ooxx.9878(新创建的线程)
当client发送数据后 rev(5,接收数据,打印完之后,又重新阻塞等待接受数据:
NIO
在操作系统层面。解决阻塞问题靠kernerl来解决。
jdk1.8:
package com.wang;import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.LinkedList;public class NIO {public static void main(String[] args) throws IOException, InterruptedException {LinkedList<SocketChannel> clients = new LinkedList<>();ServerSocketChannel ss = ServerSocketChannel.open();ss.bind(new InetSocketAddress(9090));//不阻塞ss.configureBlocking(false);ss.setOption(StandardSocketOptions.TCP_NODELAY, false);// StandardSocketOptions.SO_KEEPALIVE
// StandardSocketOptions.SO_LINGER
// StandardSocketOptions.SO_RCVBUF
// StandardSocketOptions.SO_SNDBUF
// StandardSocketOptions.SO_REUSEADDRwhile (true) {
// Thread.sleep(1000);SocketChannel client = ss.accept(); // -1 nullif (client == null) {
// System.out.println("null.....");} else {client.configureBlocking(false);int port = client.socket().getPort();System.out.println("client.port:" + port);clients.add(client);}ByteBuffer buffer = ByteBuffer.allocateDirect(4096);//遍历已连接进来的客户端for (SocketChannel c : clients) {int num = c.read(buffer); // >0 0 -1if (num > 0) {buffer.flip();byte[] bytes = new byte[buffer.limit()];buffer.get(bytes);String s = new String(bytes);System.out.println(c.socket().getPort() + " : " + s);}}}}
}
ss.configureBlocking(false);
if(client == null)
多路复用器
上述NIO中,需要轮询每个连接的客户端,不一定每个客户端都有数据发送过来,也就是每一次轮询不一定是“有效的”,造成轮询“徒劳”。
while (true) {
// Thread.sleep(1000);SocketChannel client = ss.accept(); // -1 null....//遍历已连接进来的客户端for (SocketChannel c : clients) {....
解决“徒劳”问题靠kernerl来解决。
多条路复用一个电话机:
优点:减少了系统调用的数量
弊端:每次都要传递大量的fd数据给内核
每次都要从头遍历
/**客户端*/
public class Client {public static void main(String[] args) throws Exception {//1. 获取通道SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9999));//2. 切换非阻塞模式sChannel.configureBlocking(false);//3. 分配指定大小的缓冲区ByteBuffer buf = ByteBuffer.allocate(1024);//4. 发送数据给服务端Scanner scan = new Scanner(System.in);while(scan.hasNext()){String str = scan.nextLine();buf.put((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(System.currentTimeMillis())+ "\n" + str).getBytes());buf.flip();sChannel.write(buf);buf.clear();}//5. 关闭通道sChannel.close();}
}/**服务端*/
public class Server {public static void main(String[] args) throws IOException {//1. 获取通道ServerSocketChannel ssChannel = ServerSocketChannel.open();//2. 切换非阻塞模式ssChannel.configureBlocking(false);//3. 绑定连接ssChannel.bind(new InetSocketAddress(9999));//4. 获取选择器Selector selector = Selector.open();//5. 将通道注册到选择器上, 并且指定“监听接收事件”ssChannel.register(selector, SelectionKey.OP_ACCEPT);//6. 轮询式的获取选择器上已经“准备就绪”的事件while (selector.select() > 0) {System.out.println("轮一轮");//7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”Iterator<SelectionKey> it = selector.selectedKeys().iterator();while (it.hasNext()) {//8. 获取准备“就绪”的是事件SelectionKey sk = it.next();//9. 判断具体是什么事件准备就绪if (sk.isAcceptable()) {//10. 若“接收就绪”,获取客户端连接SocketChannel sChannel = ssChannel.accept();//11. 切换非阻塞模式sChannel.configureBlocking(false);//12. 将该通道注册到选择器上sChannel.register(selector, SelectionKey.OP_READ);} else if (sk.isReadable()) {//13. 获取当前选择器上“读就绪”状态的通道SocketChannel sChannel = (SocketChannel) sk.channel();//14. 读取数据ByteBuffer buf = ByteBuffer.allocate(1024);int len = 0;while ((len = sChannel.read(buf)) > 0) {buf.flip();System.out.println(new String(buf.array(), 0, len));buf.clear();}}//15. 取消选择键 SelectionKeyit.remove();}}}
}
IO-BIO NIO相关推荐
- Java IO BIO NIO
Java IO BIO NIO 一.Java I/O概述 1.1 什么是流 1.2 流的分类 1.3 字符流 1.3.1 Reader 1.3.2 Writer 1.4 字节流 1.4.1 Input ...
- JAVA IO : BIO NIO AIO
JAVA IO : BIO NIO AIO 同步异步.阻塞非阻塞概念 同步与异步 阻塞与非阻塞 IO VS NIO VS AIO 面向流与面向缓冲 阻塞与非阻塞IO BIO.NIO.AIO的JAVA实 ...
- Java之IO,BIO,NIO,AIO知多少?
开心一笑 [一女人:"我真不放心丈夫,他准备到湖中心水最深的地方把猫扔掉."邻居:"那有什么不放心的?"女人:"猫已回家一钟头了!"] 提出 ...
- Java之IO,BIO,NIO,AIO
2019独角兽企业重金招聘Python工程师标准>>> 参考文献一 IO基础知识回顾 java的核心库java.io提供了全面的IO接口.包括:文件读写.标准设备输出等.Java中I ...
- IO: BIO ? NIO ? AIO?
IO的方式通常分为几种,同步阻塞的BIO.同步非阻塞的NIO.异步非阻塞的AIO. 一.BIO 在JDK1.4出来之前,我们建立网络连接的时候采用BIO模式,需要先在服务端启动一个ServerSock ...
- Java IO(BIO, NIO, AIO) 总结
文章转载自:JavaGuide 目录 BIO,NIO,AIO 总结 同步与异步 阻塞和非阻塞 1. BIO (Blocking I/O) 1.1 传统 BIO 1.2 伪异步 IO 1.3 代码示例 ...
- java io bio nio aio 详解
BIO.NIO.AIO的区别: BIO就是基于Thread per Request的传统server/client实现模式, NIO通常采用Reactor模式, AIO通常采用Proactor模式, ...
- java io bio nio面试题_漫画:一文学会面试中常问的 IO 问题!
原标题:漫画:一文学会面试中常问的 IO 问题! 作者 | 漫话编程 责编 | 伍杏玲 本文经授权转载自漫话编程(ID:mhcoding) 周末午后,在家里面进行电话面试,我问了面试者几个关于IO的问 ...
- Java的IO:BIO | NIO | AIO
原文: http://my.oschina.net/bluesky0leon/blog/132361 BIO | NIO | AIO,本身的描述都是在Java语言的基础上的.而描述IO,我们需要从两个 ...
- java io流区别_Java中IO流的分类和BIO,NIO,AIO的区别
到底什么是IO 我们常说的IO,指的是文件的输入和输出,但是在操作系统层面是如何定义IO的呢?到底什么样的过程可以叫做是一次IO呢? 拿一次磁盘文件读取为例,我们要读取的文件是存储在磁盘上的,我们的目 ...
最新文章
- mysql 左连接 去重复,MySQL删除左连接,3个表上的重复列
- 计算机指令格式哪几部分组成,计算机的指令格式,通常是由()两部分组成。 - 百科题库网...
- LeetCode 329. 矩阵中的最长递增路径(记忆化递归)
- 博士生是学生还是科研工作者?
- 辅助排序和Mapreduce整体流程
- 一幅漫画揭示了项目研发过程中存在的问题,太形象了
- 【JAVA】Java中goto语句的简介与使用(java 如何跳出内嵌多层循环的方法)
- linux创建云主机内存不足,云主机DC2 Linux系统CPU与内存占用率高导致无法登录
- UINavigationController与UITabbarController的样式
- 大学英语综合教程三 Unit 1至Unit 8 课文内容英译中 中英翻译
- 三目运算符 c语言求最小值,三目运算符
- 为什么微信显示这个android设备,微信显示安卓手机型号在哪设置
- 25.有5个人做在一起, 问第五个人多少岁? 他说比第四个人大2岁. 问第四个人岁数, 他说比第是三个人大2岁. 问第三个人, 又说比第二人大两岁. 问第二个人, 说比第一个人大两岁. 最后问第一个人
- 微信/QQ域名防封防拦截360不报毒任意链接跳转源码
- qt Redis使用
- AI上推荐 之 AFM与DIN模型(当推荐系统遇上了注意力机制)
- stm32中UART和USART的区别
- 自己动手做sidebar
- 笨鸟的平凡之路-简单理解什么是_consumers_offsets
- Xilinx下载电缆找不到,WARNING:iMPACT:923 - Can not find cable, check cable setup
热门文章
- 7-105 sdut-C语言实验——三个数排序7-106 sdut-C语言实验——模拟计算器7-107 sdut-C语言实验——找中间数
- hr2000 光谱Matlab,HR2000+光纤光谱仪
- 双手作业分析的作用是什么?为什么要做双手作业分析?
- 华为鸿蒙os 新闻,华为P50无限延期,谁来组成华为鸿蒙OS“头部”?
- 用简单的lnmp实现的论坛搭建
- JavaScript定时器-限时秒杀
- 论文笔记--GMAN: A Graph Multi-Attention Network for Traffic Prediction
- 微信公众平台如何配置业务域名
- js qs序列化数据 npmi qs --save
- 【转】高清混合矩阵应用于佛山市政府大礼堂会议系统解决方案