• 阻塞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. java判断用户输入的是否至少含有N位小数

    判断用户输入的是否至少含有N位小数. 1.当用户输入的是非数字时抛出异常,返回false. 2.当用户输入数字是,判断其数字是否至少含有N位小数,如果不含有,返回false. 3.当用户输入的数字的小 ...

  2. Mycat 配置说明(rule.xml)

    rule.xml 配置文件定义了我们对表进行拆分所涉及到的规则定义.我们可以灵活的对表使用不同的分片算法, 或者对表使用相同的算法但具体的参数不同. tableRule 标签 该标签用于定义表的拆分规 ...

  3. 使用了旧版nuget的.net项目在git中的问题

    曾几何时,使用nuget包管理项目依赖还需要将nuget执行程序及其配置文件包含在项目中. 如上图所示,在解决方案文件夹中,有专门为nuget程序设置的 .nuget 子目录. 当将项目纳入git管理 ...

  4. poj-1218 THE DRUNK JAILER 喝醉的狱卒

    自己去看看原题; 题目大意: 就是一个狱卒喝醉了,他第一趟吧所有的监狱都带开,第二趟把能把二整除的监狱关闭,第三趟操作能把三整除的监狱; 求最后能逃跑的罪犯数 输入第一个数是代表 测试数据组数 每个数 ...

  5. SpringBoot 自定义Banner

    在2016年的最后一天,借用Spring Boot的Banner向各位程序猿同仁们问候一声:Happy New Year. 接下来我们就来介绍一下这个轻松愉快的自定义banner功能.实现的方式非常简 ...

  6. TCP为什么不是两次握手而是三次?

    为什么不采用两次握手?如果是两次握手的情景:客户端在发送一个连接建立请求之后进入等待状态,等到服务端确认之后就进入established状态.服务端在发送一个确认连接建立请求报文之后(不管客户端是否有 ...

  7. 使用Java编译思想

    1.Java常见的注释有哪些,语法是怎样的? 1)单行注释用//表示,编译器看到//会忽略该行//后的所文本 2)多行注释/* */表示,编译器看到/*时会搜索接下来的*/,忽略掉/* */之间的文本 ...

  8. NSURLSession http转Https

    1.设置代理 NSURLSession *sesson = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defa ...

  9. 新事物学习---WebApp移动端手势Hammer

    花落水流红,闲愁万种,无语怨东风. Hammer介绍 Hammer库是一个移动端手势库,移动端的手势操作(比如touch,tap,拖动,滑动等等)都可以用这个库,而我们不用关心,它的底层方案具体是怎么 ...

  10. C#委托的使用及案例

    C#委托 1.委托就是把方法当做方法的参数来传递, 做自己不想做的事,是存有对某个方法的引用的一种引用类型变量.引用可在运行时被改变. 所有的委托都派生自System.Delegate类 委托的声明 ...