• 阻塞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的更多相关文章

  1. 如何解读 Java IO、NIO 中的同步阻塞与同步非阻塞?

    原文链接:如何解读 Java IO.NIO 中的同步阻塞与同步非阻塞? 一.前言 最近刚读完一本书:<Netty.Zookeeper.Redis 并发实战>,个人觉得 Netty 部分是写 ...

  2. NIO之阻塞IO与非阻塞IO(包含Selector使用)

    阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...

  3. 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?

    通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...

  4. 阻塞式和非阻塞式IO

    有很多人把阻塞认为是同步,把非阻塞认为是异步:个人认为这样是不准确的,当然从思想上可以这样类比,但方式是完全不同的,下面说说在JAVA里面阻塞IO和非阻塞IO的区别 在JDK1.4中引入了一个NIO的 ...

  5. 深入理解非阻塞同步IO和非阻塞异步IO

    这两篇文章分析了Linux下的5种IO模型 http://blog.csdn.net/historyasamirror/article/details/5778378 http://blog.csdn ...

  6. 阻塞IO,非阻塞IO,异步IO和非异步IO 的区别

    最近在研究java IO.NIO.NIO2(或者称AIO)相关的东西,有些概念还是要明确下. 按照<Unix网络编程>的划分,IO模型可以分为:阻塞IO.非阻塞IO.IO复用.信号驱动IO ...

  7. 5种IO模型、阻塞IO和非阻塞IO、同步IO和异步IO

    POSIX 同步IO.异步IO.阻塞IO.非阻塞IO,这几个词常见于各种各样的与网络相关的文章之中,往往不同上下文中它们的意思是不一样的,以致于我在很长一段时间对此感到困惑,所以想写一篇文章整理一下. ...

  8. 阻塞IO和非阻塞IO的区别

    转载地址: http://blog.sina.com.cn/s/blog_a46817ff0101g0gv.html http://blog.csdn.net/nodeathphoenix/artic ...

  9. 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...

  10. 转 网络IO模型:同步IO和异步IO,阻塞IO和非阻塞IO

    此文章为转载,如有侵权,请联系本人.转载出处,http://blog.chinaunix.net/uid-28458801-id-4464639.html 同步(synchronous) IO和异步( ...

随机推荐

  1. ER图

    E-R图也称实体-联系图(Entity Relationship Diagram), 提供了表示实体类型.属性和联系的方法,用来描述现实世界的概念模型. 它是描述现实世界概念结构模型的有效方法.是表示 ...

  2. mybatis学习日记-day01

    Mybatis说明: MyBatis 使用简单的 XML或注解用于配置和原始映射,将接口和 Java 的POJOs(Plain Old Java Objects,普通的 Java对象)映射成数据库中的 ...

  3. 关于 BigDecimal处理float、double数据

    Big Decimal 在java中,对于float与double中的数据,总会因为精度问题而丢失数据的准确性,也就是说对于两者所处理的得到的值是无限接近于那个数,而并非一个精确数字,而对于电商中所涉 ...

  4. laravel-Policy步骤

    用户授权Policy 定义策略类 php artisan make:policy <name> 定义方法 注册策略类和模型关联 app > Providers > AuthSe ...

  5. 笔记:Spring Cloud Ribbon RestTemplate 详解

    详细介绍RestTemplate 针对几种不同请求类型和参数类型的服务调用实现,示例代码中的 restTemplate 都是通过Spring 注入方式创建的,相关代码如下: @Autowired pr ...

  6. JavaSE语法基础(3)---函数、数组

    JavaSE语法基础(3)---函数.数组 函数的概念:实现特定功能的一段代码,可反复使用. 函数的出现减少代码冗余,提高代码的复用性,可读性,可维护性,可以使每个功能模块独立起来,方便分工合作. 函 ...

  7. 安装texlive2017(latex的编译软件)

    准备工作是先卸载老版本的texlive,这个只要找到原来安装时的安装目录,然后直接把整个文件夹删掉即可.然后找到最近的Ctan的镜像,下载到对应版本的texlive,例如Mac系统,最好用的就是tex ...

  8. python 函数基础 定义

    一.函数介绍 1.为什么要有函数? 没有函数的代码组织结构不清晰,可读性差. 代码冗余 管理维护难度大,扩展性 2.什么是函数? 具备某一个功能的工具就是程序中的函数. 事先准备工具的过程就是:函数的 ...

  9. 2018上C语言程序设计(高级)博客作业样例

    要求一(20分) 完成PTA中题目集名为<usth-C语言高级-第1次作业>中的所有题目. 要求二 PTA作业的总结(20分+30分) 将PTA第1次作业作业中以下2道题的解题思路按照规定 ...

  10. 【Alpha】咸鱼冲刺日记第一天-黄紫仪

    总汇链接 一,合照 emmmmm.自然是没有的. 二,项目燃尽图 emmmmm,事实上它还没有正式开始.所以依旧没有[突然觉得明天任务真重] 三,项目进展 emmmmm,我错了咸鱼了两天才突然反应过来 ...