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和异步( ...
随机推荐
- Unity的常用API
1.Event Function:事件函数 Reset() :被附加脚本时.在游戏物体的组件上按Reset时会触发该事件函数 Start() :在游戏初始化时会执行一次 Update() :每一帧 ...
- Java基础知识回顾之二 ----- 修饰符和String
前言 在上一篇中,回顾了Java的基本数据类型 ,这篇就来回顾下Java中的一些修饰符以及String. 修饰符介绍 Java修饰符主要分为两类: 访问修饰符 非访问修饰符 其中访问修饰符主要包括 p ...
- Servlet的三个域对象
我们在开发javaweb项目的时候,经常会遇到jsp和Servet之间互相传值,既然有传值,就要有对象来传,这里先说Servlet的三大域对象,request,session,application他 ...
- 微信小程序学习笔记(阶段二)
二阶段学习过程: (一)看官方文档的框架.组件.API:https://mp.weixin.qq.com/debug/wxadoc/dev/ (二)看极客学院第3.4章视频:http://www.ph ...
- Dijkstra算法 Java实现
public class Dijkstra { private static int N = 1000; private static int[][] Graph = { { 0, 1, 5, N, ...
- 【Python】 配置解析ConfigParser & 命令行参数解析optparser
ConfigParser ConfigParser包装了配置文件的读取和写入,使得python程序可以更加轻松操作配置文件了.这里的配置文件是指.ini的那种文件,基本格式如下 [section_a] ...
- Axure RP简单作品
点击按钮,同时出现1-7 点击按钮,依次出现1-7,
- canvas填充样式
填充样式主要针对fillStyle.fillStyle除了可以赋值为color,还可以赋值渐变色,包括线性渐变色和径向渐变色,还是和css3里的内容类似. 一.线性渐变 1.设置线性渐变的填充样式 设 ...
- js和jquery判断checkbox是否被选中
js判断: if(document.getElementById("checkboxID").checked){ alert("checkbox is checked&q ...
- (译文)开始学习Vue.js特性--Scoped Slots
什么是scoped slots A scoped slot is a special type of slot that functions as a reusable template (that ...