1. 传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。
  2. Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。

选择器(Selector)

  1. 选择器(Selector) 是 SelectableChannle 对象的多路复用器,Selector 可以同时监控多个 SelectableChannel 的 IO 状况,也就是说,利用 Selector可使一个单独的线程管理多个 Channel。Selector 是非阻塞 IO 的核心。
  2. SelectableChannle 的结构如下图:

阻塞式IO流操作示例:

  1. package com.soyoungboy.nio;
  2.  
  3. import java.io.IOException;
  4. import java.net.InetSocketAddress;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.FileChannel;
  7. import java.nio.channels.ServerSocketChannel;
  8. import java.nio.channels.SocketChannel;
  9. import java.nio.file.Paths;
  10. import java.nio.file.StandardOpenOption;
  11.  
  12. import org.junit.Test;
  13.  
  14. public class TestBlockingNIO2 {
  15.  
  16. //客户端
  17. @Test
  18. public void client() throws IOException{
  19. SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
  20.  
  21. FileChannel inChannel = FileChannel.open(Paths.get("1.jpg"), StandardOpenOption.READ);
  22.  
  23. ByteBuffer buf = ByteBuffer.allocate(1024);
  24.  
  25. while(inChannel.read(buf) != -1){
  26. buf.flip();
  27. sChannel.write(buf);
  28. buf.clear();
  29. }
  30.  
  31. sChannel.shutdownOutput();
  32.  
  33. //接收服务端的反馈
  34. int len = 0;
  35. while((len = sChannel.read(buf)) != -1){
  36. buf.flip();
  37. System.out.println(new String(buf.array(), 0, len));
  38. buf.clear();
  39. }
  40.  
  41. inChannel.close();
  42. sChannel.close();
  43. }
  44.  
  45. //服务端
  46. @Test
  47. public void server() throws IOException{
  48. ServerSocketChannel ssChannel = ServerSocketChannel.open();
  49.  
  50. FileChannel outChannel = FileChannel.open(Paths.get("2.jpg"), StandardOpenOption.WRITE, StandardOpenOption.CREATE);
  51.  
  52. ssChannel.bind(new InetSocketAddress(9898));
  53.  
  54. SocketChannel sChannel = ssChannel.accept();
  55.  
  56. ByteBuffer buf = ByteBuffer.allocate(1024);
  57.  
  58. while(sChannel.read(buf) != -1){
  59. buf.flip();
  60. outChannel.write(buf);
  61. buf.clear();
  62. }
  63.  
  64. //发送反馈给客户端
  65. buf.put("服务端接收数据成功".getBytes());
  66. buf.flip();
  67. sChannel.write(buf);
  68.  
  69. sChannel.close();
  70. outChannel.close();
  71. ssChannel.close();
  72. }
  73.  
  74. }

非阻塞式IO流

一、使用 NIO 完成网络通信的三个核心:

1. 通道(Channel):负责连接

  java.nio.channels.Channel 接口:
    |--SelectableChannel
    |--SocketChannel
    |--ServerSocketChannel
    |--DatagramChannel

    |--Pipe.SinkChannel
    |--Pipe.SourceChannel

2. 缓冲区(Buffer):负责数据的存取

3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况

  1. public class TestNonBlockingNIO {
  2.  
  3. //客户端
  4. @Test
  5. public void client() throws IOException{
  6. //1. 获取通道
  7. SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
  8.  
  9. //2. 切换非阻塞模式
  10. sChannel.configureBlocking(false);
  11.  
  12. //3. 分配指定大小的缓冲区
  13. ByteBuffer buf = ByteBuffer.allocate(1024);
  14.  
  15. //4. 发送数据给服务端
  16. Scanner scan = new Scanner(System.in);
  17.  
  18. while(scan.hasNext()){
  19. String str = scan.next();
  20. buf.put((new Date().toString() + "\n" + str).getBytes());
  21. buf.flip();
  22. sChannel.write(buf);
  23. buf.clear();
  24. }
  25.  
  26. //5. 关闭通道
  27. sChannel.close();
  28. }
  29.  
  30. //服务端
  31. @Test
  32. public void server() throws IOException{
  33. //1. 获取通道
  34. ServerSocketChannel ssChannel = ServerSocketChannel.open();
  35.  
  36. //2. 切换非阻塞模式
  37. ssChannel.configureBlocking(false);
  38.  
  39. //3. 绑定连接
  40. ssChannel.bind(new InetSocketAddress(9898));
  41.  
  42. //4. 获取选择器
  43. Selector selector = Selector.open();
  44.  
  45. //5. 将通道注册到选择器上, 并且指定“监听接收事件”
  46. ssChannel.register(selector, SelectionKey.OP_ACCEPT);
  47.  
  48. //6. 轮询式的获取选择器上已经“准备就绪”的事件
  49. while(selector.select() > 0){
  50.  
  51. //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
  52. Iterator<SelectionKey> it = selector.selectedKeys().iterator();
  53.  
  54. while(it.hasNext()){
  55. //8. 获取准备“就绪”的是事件
  56. SelectionKey sk = it.next();
  57.  
  58. //9. 判断具体是什么事件准备就绪
  59. if(sk.isAcceptable()){
  60. //10. 若“接收就绪”,获取客户端连接
  61. SocketChannel sChannel = ssChannel.accept();
  62.  
  63. //11. 切换非阻塞模式
  64. sChannel.configureBlocking(false);
  65.  
  66. //12. 将该通道注册到选择器上
  67. sChannel.register(selector, SelectionKey.OP_READ);
  68. }else if(sk.isReadable()){
  69. //13. 获取当前选择器上“读就绪”状态的通道
  70. SocketChannel sChannel = (SocketChannel) sk.channel();
  71.  
  72. //14. 读取数据
  73. ByteBuffer buf = ByteBuffer.allocate(1024);
  74.  
  75. int len = 0;
  76. while((len = sChannel.read(buf)) > 0 ){
  77. buf.flip();
  78. System.out.println(new String(buf.array(), 0, len));
  79. buf.clear();
  80. }
  81. }
  82.  
  83. //15. 取消选择键 SelectionKey
  84. it.remove();
  85. }
  86. }
  87. }
  88. }

Java NIO -- 阻塞和非阻塞的更多相关文章

  1. 关于同步,异步,阻塞,非阻塞,IOCP/epoll,select/poll,AIO ,NIO ,BIO的总结

    相关资料 IO基本概念 Linux环境 同步异步阻塞非阻塞 同步与异步 阻塞与非阻塞 IO模型Reference Link 阻塞IO模型 非阻塞IO模型 IO复用模型 信号驱动异步IO模型 异步IO模 ...

  2. java网络通信:异步非阻塞I/O (NIO)

    转: java网络通信:异步非阻塞I/O (NIO) 首先是channel,是一个双向的全双工的通道,可同时读写,而输入输出流都是单工的,要么读要么写.Channel分为两大类,分别是用于网络数据的S ...

  3. 【IBM】Merlin 给 Java 平台带来了非阻塞 I/O

    Merlin 给 Java 平台带来了非阻塞 I/O 新增的功能大幅降低了线程开销 Java 技术平台早就应该提供非阻塞 I/O 机制了.幸运的是,Merlin(JDK 1.4)有一根几乎在各个场合都 ...

  4. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别参考

    参考https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral IO复用,AI ...

  5. IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别(百度)

    如果面试问到IO操作,这篇文章提到的问题,基本是必问,百度的面试官问我三个问题 (1)什么是NIO(Non-blocked IO),AIO,BIO (2) java IO 与 NIO(New IO)的 ...

  6. JAVA NIO学习记录2-非阻塞式网络通信

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

  7. Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程

    Socket-IO 系列(三)基于 NIO 的同步非阻塞式编程 缓冲区(Buffer) 用于存储数据 通道(Channel) 用于传输数据 多路复用器(Selector) 用于轮询 Channel 状 ...

  8. (转)IO复用,AIO,BIO,NIO,同步,异步,阻塞和非阻塞 区别

    本文来自:https://www.cnblogs.com/aspirant/p/6877350.html?utm_source=itdadao&utm_medium=referral,非常感谢 ...

  9. NIO:异步非阻塞I/O,AIO,BIO

    Neety的基础使用及说明 https://www.cnblogs.com/rrong/p/9712847.html BIO(缺乏弹性伸缩能力,并发量小,容易出现内存溢出,出现宕机 每一个客户端对应一 ...

  10. Java中的阻塞和非阻塞IO包各自的优劣思考(经典)

    Java中的阻塞和非阻塞IO包各自的优劣思考 NIO 设计背后的基石:反应器模式,用于事件多路分离和分派的体系结构模式. 反应器(Reactor):用于事件多路分离和分派的体系结构模式 通常的,对一个 ...

随机推荐

  1. SDP服务搜索流程源码分析

    BREDR的设备 在进行配对完成之后,进行;连接之前都要进行服务的搜索,服务搜索走的流程是SDP,这篇文章就分析一下,bluedroid中SDP的代码流程,我们从配对完成的回调函数开始分析: /*** ...

  2. 调用不同目录类的protected构造器

    一.问题 二.分析 调用不同目录类的protected构造器,IDE报错. 二.解决办法: 后面添加一个{}就可以了

  3. 全自动数据表格JQuery版

    由于最近工作上有些变动,已经快一个月没有写博客了.上一篇博客[React]全自动数据表格组件——BodeGrid介绍了全自动数据表格的设计思路以及分享了一个react.js的实现.但是现实情况中为了节 ...

  4. zookeeper 动态管理nginx配置

    假设我们有一个场景,所有服务器共享同一份配置文件,我们肯定不可能单独手动维护每台服务器,这时可以利用zookeeper的配置管理功能. 环境:python + nginx + zookeeper 目的 ...

  5. Vue Element Tabe Pager 分页方案

    表格和分页分离的,但是使用中,却是结合在一起的. 分析 有以下方式触发查询: mounted 加载数据. 查询按钮 加载数据. pager 变化加载数据 加载数据函数: loadData 问题 mou ...

  6. mac系统下修复第三方Python包bug

    发现问题 今天在github上fork了CI 3.x的中文手册,按照README文档一步步进行Sphinx和相关工具的安装,最终build生成html版手册.操作到第6步执行`make html`的时 ...

  7. 冲刺Two之站立会议9

    今天我们团队主要针对软件的功能进行了改进.因为它目前可以实现视频通话,语音聊天,文件传输和文字聊天的通信功能,我们想要在它的基础上实现临时局域群聊和群聊视频的功能,目前还没有完全实现.

  8. (转)SqlDateTime 溢出。必须介于 1/1/1753 12:00:00 AM 和 12/31/9999 11:59:59 PM之间

    原因: 出现这种问题多半是因为你插入或者更新数据库时,datetime字段值为空默认插入0001年01月01日造成datetime类型溢出. 传给数据库表的时间类型值是null值.这里的null指的是 ...

  9. the confilict between validation and readonly in jquery

    How can I disable jquery validation on readonly fields? http://stackoverflow.com/questions/10803294/ ...

  10. jQuery中click事件多次触发解决方案

    jQuery 中元素的click事件中绑定其他元素的click事件. 因为jQuery中的click事件会累计绑定,导致事件注册越来越多. 解决方案: 1.能够避开,避免把click事件绑定到其他元素 ...