Java-NIO(七):阻塞IO与非阻塞IO
- 阻塞IO
传统的 IO 流都是阻塞式的。
也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。
因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
注意:在阻塞IO操作的过程中,用来提高程序的解决方案一般是使用多线程来处理,但是开辟线程也是比较耗费资源的。
测试NIO阻塞模式:
@Test
public void client() throws IOException {
// 1、获取通道(channel)
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
FileChannel inChannel = FileChannel.open(Paths.get("Java NIO.pdf"),StandardOpenOption.READ); // 2、分配指定大小的缓冲区
ByteBuffer byteBuffer=ByteBuffer.allocate(1024); // 3、读取本地文件,并写入发送channel
while (inChannel.read(byteBuffer)!=-1) {
byteBuffer.flip();// 切换到读模式
socketChannel.write(byteBuffer);
byteBuffer.clear();// 清空缓冲区
} // 必须shutdown否则就没法切换到接收数据的模式
socketChannel.shutdownOutput(); System.out.println("client waiting reading server response");
// 接收服务端的数据
int length=0;
while((length=socketChannel.read(byteBuffer))!=-1){
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(),0,length));
byteBuffer.clear();
} System.out.println("end...");
inChannel.close();
socketChannel.close();
} @Test
public void server() throws IOException{
// 1、获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
FileChannel outChannel=FileChannel.open(Paths.get("33.pdf"), StandardOpenOption.READ,StandardOpenOption.WRITE,StandardOpenOption.CREATE); // 2、绑定连接
serverSocketChannel.bind(new InetSocketAddress(9898));
// 3、获取客户端的连接
SocketChannel accept = serverSocketChannel.accept(); // 4、分配指定大小的缓冲区
ByteBuffer byteBuffer= ByteBuffer.allocate(1024);
// 5、接收客户端的数据,并保存到本地
while (accept.read(byteBuffer)!=-1) {
byteBuffer.flip();
outChannel.write(byteBuffer);
byteBuffer.clear();
} System.out.println("server print ..."); byteBuffer.put("server success".getBytes());
byteBuffer.flip();//切换到读模式
accept.write(byteBuffer); // 6、关闭连接
accept.close();
outChannel.close();
serverSocketChannel.close();
}
打印结果:
client waiting reading server response
server success
end...
- 非阻塞
Java NIO 是非阻塞模式的。
当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。
因此, NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。
- 如何形成非阻塞IO:

从上边的图中我们知道要构成NIO非阻塞模式,必须要引入Selector。那么,什么是Selector?
- 选择器(Selector)
选择器(Selector)是SelectableChannle对象的多路复用器,Selector可以同时监控多个SelectableChannel的IO状况,也就是说,利用Selector可以一个单独的线程管理多个Channel。Selector是非阻塞IO的核心。
- 使用NIO实现网络通信的三个核心:
1、通道(channel):负责连接
java.nio.channels.Channel接口:
|--SelectableChannel
|--SocketChannel
|--ServerSocketChannel
|--DatagramChannel
|--Pipe.SinkChannel
|--Pipe.SourceChannel
2、缓冲区(Buffer):负责数据的存储
3、选择器(Selector):是SelectableChannel的多路复用器。用于监控SelectableChannel的IO状况。
- 非阻塞IO示例:
/**
* 客户端
*/
@Test
public void client() throws IOException {
// 1、获取通道(channel)
SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
// 2、切换成非阻塞模式
socketChannel.configureBlocking(false); // 3、分配指定大小的缓冲区
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
byteBuffer.put("你可理论上的 。。。".getBytes());
byteBuffer.flip();
socketChannel.write(byteBuffer); socketChannel.close();
} @Test
public void server() throws IOException {
// 1、获取通道
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
// 2.设置为非阻塞
serverSocketChannel.configureBlocking(false);
// 3、绑定连接
serverSocketChannel.bind(new InetSocketAddress(9898)); // 4、获取Selector选择器
Selector selector = Selector.open(); // 5、将通道注册到选择器上,并制定监听事件为:“接收”事件
serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); // 6、采用轮询的方式获取选择器上“准备就绪”的任务
while (selector.select() > 0) {
// 7、获取当前选择器中所有注册的选择键(“已经准备就绪的事件”)
Iterator<SelectionKey> selectedKeys = selector.selectedKeys().iterator();
while (selectedKeys.hasNext()) {
// 8、获取“准备就绪”的时间
SelectionKey selectedKey = selectedKeys.next(); // 9、判断key是具体的什么事件
if (selectedKey.isAcceptable()) {
// 10、若接受的事件是“接收就绪”事件,就获取客户端连接
SocketChannel socketChannel = serverSocketChannel.accept();
// 11、切换为非阻塞模式
socketChannel.configureBlocking(false);
// 12、将该通道注册到selector选择器上
socketChannel.register(selector, SelectionKey.OP_READ);
} else if (selectedKey.isReadable()) {
// 13、获取该选择器上的“读就绪”状态的通道
SocketChannel socketChannel = (SocketChannel) selectedKey.channel(); // 14、读取数据
ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
int length = 0;
while ((length = socketChannel.read(byteBuffer)) != -1) {
byteBuffer.flip();
System.out.println(new String(byteBuffer.array(), 0, length));
byteBuffer.clear();
}
socketChannel.close();
} // 15、移除选择键
selectedKeys.remove();
}
} // 7、关闭连接
serverSocketChannel.close();
}
Java-NIO(七):阻塞IO与非阻塞IO的更多相关文章
- 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?
原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...
- NIO之阻塞IO与非阻塞IO(包含Selector使用)
阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...
- 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?
通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...
- 阻塞式和非阻塞式IO
有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...
- 深入理解非阻塞同步IO和非阻塞异步IO
这两篇文章分析了Linux下的5种IO模型 http://blog.csdn.net/historyasamirror/article/details/5778378 http://blog.csdn ...
- 阻塞IO,非阻塞IO,异步IO和非异步IO 的区别
最近在研究java IO.NIO.NIO2(或者称AIO)相关的东西,有些概念还是要明确下. 按照<Unix网络编程>的划分,IO模型可以分为:阻塞IO.非阻塞IO.IO复用.信号驱动IO ...
- 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO
POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. ...
- 阻塞IO和非阻塞IO的区别
转载地址: http://blog.sina.com.cn/s/blog_a46817ff0101g0gv.html http://blog.csdn.net/nodeathphoenix/artic ...
- 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...
- 转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO
此文章为转载,如有侵权,请联系本人.转载出处,http://blog.chinaunix.net/uid-28458801-id-4464639.html 同步(synchronous) IO和异步( ...
随机推荐
- 自定义TabBar之理解hittest
需求的TabBar是这样的:5个 tabItem, 中间的那个 item 部分超出系统默认TabBar的上边界. 那么实现的关键点就是如何在点击它突出的部分的时候,也可以正常获得响应.我来把问题简化, ...
- LinkedList源码解析(JDK1.8)
package java.util; import java.util.function.Consumer; /** * LinkedList是List和Deque接口的双向链表的实现.实现了所有可选 ...
- POJ-1256 next_permutation函数应用
字典序列: 在字典序中蕴含着一个点,就是大小的问题,谁先出现,谁后出现的问题.譬如a<b<c,出现顺序就是a,b,c. 本题中字符集是所有大小写字母,而题目中规定的谁大谁小已经不是按asc ...
- python web开发-flask连接sqlite数据库
在之前的文章中我们介绍了如何在centOS中安装sqlite数据库. Sqlite安装完成后,本节就用flask来连接和操作sqlite数据库. 1. 数据准备 先在sqlite3中创建一 ...
- java 语法分析器 括号匹配
package test; import java.util.*;public class Test { public String text="fewe{f(sdd(f)a[j]sd ...
- 【Java实现】栈和队列就是这么简单
一.前言 上一篇已经讲过了链表[Java实现单向链表]了,它跟数组都是线性结构的基础,本文主要讲解线性结构的应用:栈和队列 如果写错的地方希望大家能够多多体谅并指正哦,如果有更好的理解的方式也希望能够 ...
- React Native 轻松集成统计功能(iOS 篇)
最近产品让我加上数据统计功能,刚好极光官方支持数据统计 支持了 React Native 版本 第一步 安装: 在你的项目路径下执行命令: npm install janalytics-react-n ...
- Git 建立仓库及常用命令速查表
Git新建仓库两种模式: 一.项目在本地时,本地初始化仓库并提交至Coding.Net 新建一个空白目录并进入,执行如下流程 1.git init2.项目代码复制到当前目录3.git add *4.g ...
- [福大软工教学] W班 第1次成绩排行榜
作业地址 https://edu.cnblogs.com/campus/fzu/FZUSoftwareEngineering1715W/homework/837 作业要求 (1)回想一下你初入大学时对 ...
- Python split()方法
Python split()方法 描述 Python split()通过指定分隔符对字符串进行切片,如果参数num 有指定值,则仅分隔 num 个子字符串 语法 split()方法语法: str.sp ...