1         非阻塞NIO和阻塞IO

1.1           定义

阻塞IO:线程被阻塞,去处理一个读取和写入,中间如果有等待时间,则线程被占用,也不能处理其他任务;

非阻塞IO(new IO):引入了通道的概念,一个连接对应一个通道,为每个通道配置缓冲区,线程去轮询查看的通道的状态,如果某个通道上有数据准备好了,则通道状态会发生改变,线程就去处理这个读写操作;

1.2           非阻塞实现的核心Selector

Selector 一般称为选择器 ,或者多路复用器。在通道上建立socket连接,然后调用channel.register(selector, Selectionkey.OP_READ);将通道注册到Selector上,并且申明这个连接是读(READ)、写(WRITE)、接受(ACCEPT)、连接(     CONNECT),或者四个功能都包括;这样就可以用一个线程,一个Selector去管理多个连接;selector会去循环查询各个通道的状态,如果通道状态发生改变,会去判断通道的类型(读、写、接受、连接),然后再对应去做处理;

(1)Selector的创建

通过调用Selector.open()方法创建一个Selector对象,如下:

Selector selector = Selector.open();

(2)注册Channel到Selector

channel.configureBlocking(false);

SelectionKey key = channel.register(selector, Selectionkey.OP_READ);

第二个参数是通道的类型,有四个值,方便位运算;

读 : SelectionKey.OP_READ ( 1)

写 : SelectionKey.OP_WRITE ( 4)

连接 : SelectionKey.OP_CONNECT ( 8)

接收 : SelectionKey.OP_ACCEPT ( 16)

若注册时不止监听一个事件,则可以使用“位或”操作符连接。

1.3           SelectableChannle通道上建立连接

(1)非阻塞通道

AbstractSelectableChannel抽象类继承了SelectableChannle接口, SocketChannel、ServerSocketChannel、DatagramChannel都是直接继承了 AbstractSelectableChannel抽象类 。SocketChannel是用于socket客户端,ServerSocketChannel是用于socket服务器;

(2)阻塞通道

FileChannel还是不能实现非阻塞,对文件的读写IO,不能同时写入一个文件。

1.4           SelectionKey通道状态

SelectionKey 代表各个通道的状态信号,通过调用选择器的函数来获取到所有有信号的通道的状态,Set<SelectionKey> keys = selector.selectedKeys();然后在通过SelectionKey的方法去判断是哪种信号。

(1)key.attachment(); //返回SelectionKey的attachment,attachment可以在注册channel的时候指定。

(2)key.channel(); // 返回该SelectionKey对应的channel。

(3)key.selector(); // 返回该SelectionKey对应的Selector。

(4)key.interestOps(); //返回代表需要Selector监控的IO操作的bit mask

我们可以通过与操作来判断Selector是否对Channel的某种事件感兴趣,感兴趣的boolean为1;

int interestSet = selectionKey.interestOps();

boolean isInterestedInAccept = (interestSet & SelectionKey.OP_ACCEPT) == SelectionKey.OP_ACCEPT;

boolean isInterestedInConnect = interestSet & SelectionKey.OP_CONNECT;

boolean isInterestedInRead = interestSet & SelectionKey.OP_READ;

boolean isInterestedInWrite = interestSet & SelectionKey.OP_WRITE;

(5)key.readyOps(); // 返回一个bit mask,代表在相应channel上可以进行的IO操作。可以通过与运算去判断是否准备好;

(6)直接调用SelectionKey对象的函数判断信号状态

boolean isReadable() 检测 Channal 中读事件是否就绪

boolean isWritable() 检测 Channal 中写事件是否就绪

boolean isConnectable() 检测 Channel 中连接是否就绪

boolean isAcceptable() 检测 Channel 中接收是否就绪

1.5           阻塞IO使用实例

客户端向服务器端发送一张图片
package com.happybks.nio.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
 
import org.junit.Test;
 
public class TestBlockingNIO {
 
         //客户端
         @Test
         public void client() throws IOException{
                         //1、获取通道(open这种方法是jdk1.7之后才引入的)
                         SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 8888));
                         
                         //2、分配指定大小的缓冲区
                         ByteBuffer buf=ByteBuffer.allocate(1024);
                         
                         //3、从本地读取文件,并发送到服务端
                         FileChannel inFileChannel=FileChannel.open(Paths.get("D:/Test/NIO/1.jpg"), StandardOpenOption.READ);
                         while(inFileChannel.read(buf)!=-1){
                                        buf.flip();
                                        socketChannel.write(buf);
                                        buf.clear();
                         }
                         
                         //在阻塞IO下,如果关闭socketChannel,那么服务端不知道客户端是否已经把所有数据发完,所以会一直阻塞。
                         socketChannel.shutdownOutput();
                         //另一种方法就是把这个线程切换成非阻塞模式
                         
                         
                         //接收服务端反馈
                         int len = 0;
                         while((len = socketChannel.read(buf)) !=-1){
                                        buf.flip();
                                        System.out.println(new String(buf.array(),0,len));
                         }
                         
                         //4、关闭通道
                         inFileChannel.close();
                         socketChannel.close();
         }
         
         //服务端
         @Test
         public void server() throws IOException{
                         //1、获取端口
                         ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
         
                         //2、绑定连接
                         serverSocketChannel.bind(new InetSocketAddress(8888));
                         
                         //3、获取客户端连接的通道
                         SocketChannel socketChannel = serverSocketChannel.accept();
                         
                         //4、接收客户端的数据,保存到本地。(提到本地,就要弄个FileChannel)
                         FileChannel outFileChannel = FileChannel.open(Paths.get("D:/Test/NIO/2.jpg"), StandardOpenOption.WRITE,StandardOpenOption.CREATE);
                         ByteBuffer buf=ByteBuffer.allocate(1024);
                         while(socketChannel.read(buf)!=-1){
                                        buf.flip();
                                        outFileChannel.write(buf);
                                        buf.clear();
                         }
                         
                         //发送反馈给客户端
                         buf.put("服务端接收数据成功!".getBytes());
                         buf.flip();
                         socketChannel.write(buf);
                         
                         socketChannel.close();
                         outFileChannel.close();
                         serverSocketChannel.close();
                         
         }
}

1.6           非阻塞IO使用实例

package com.happybks.nio.nio;

import java.io.IOException;

import java.net.InetSocketAddress;

import java.nio.ByteBuffer;

import java.nio.channels.SelectionKey;

import java.nio.channels.Selector;

import java.nio.channels.ServerSocketChannel;

import java.nio.channels.SocketChannel;

import java.util.Date;

import java.util.Iterator;

import org.junit.Test;

public class TestNonBlockingNIO {

//客户端

@Test

public  void client() throws IOException{

//1、获取通道

SocketChannel socketChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1",8888));

//2、切换非阻塞模式

socketChannel.configureBlocking(false);

//3、分配指定大小的缓冲区

ByteBuffer buf=ByteBuffer.allocate(1024);

//4、发送数据服务器

buf.put(new Date().toString().getBytes());

buf.flip();

socketChannel.write(buf);

buf.clear();

//5、关闭通道

socketChannel.close();

}

//服务端

@Test

public  void server() throws IOException{

//1、获取通道

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

//2、切换非阻塞模式

serverSocketChannel.configureBlocking(false);

//3、绑定连接

serverSocketChannel.bind(new InetSocketAddress(8888));

//4、获取选择器

Selector selector = Selector.open();

//5、将通道注册到选择器上(第二个选项参数叫做选择键,用于告诉选择器需要监控这个通道的什么状态或者说什么事件(读、写、连接、接受))

//选择键是整型值,如果需要监控该通道的多个状态或事件,可以将多个选择键用位运算符“或”“|”来连接

//这里服务端首先要监听客户端的接受状态

serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

//6、轮询式地获取选择器上已经“准备就绪”的事件

while(selector.select() > 0){

//7、获取当前选择中所有注册的“选择键(已就绪的监听事件)”

Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

while(iterator.hasNext()){

//8、获取准备“就绪”的是事件

SelectionKey sk=iterator.next();

//9、判断是什么事件准备就绪

if(sk.isAcceptable()){

//10、若接受就绪,获取客户端连接

SocketChannel socketChannel = serverSocketChannel.accept();

//11、客户端连接socketChannel也需要切换非阻塞模式

socketChannel.configureBlocking(false);

//12、将该通道注册到选择器上,监控客户端socketChannel的读就绪事件

socketChannel.register(selector, SelectionKey.OP_READ);

}

else if(sk.isReadable()){

//13、获取当前选择器上“读就绪”状态的通道

              SocketChannel socketChannel = (SocketChannel) sk.channel();

//14、读取数据

ByteBuffer buf=ByteBuffer.allocate(1024);

int len=0;

while((len=socketChannel.read(buf))>0){

buf.flip();

System.out.println(new String(buf.array(),0,len));

buf.clear();

}

}

//15、取消选择键SelectionKey

iterator.remove();

}

}

}

}

自己开发了一个股票智能分析软件,功能很强大,需要的点击下面的链接获取:

https://www.cnblogs.com/bclshuai/p/11380657.html

百度云盘下载地址:

链接:https://pan.baidu.com/s/1swkQzCIKI3g3ObcebgpIDg

提取码:mc8l

微信公众号获取最新的软件和视频介绍

QStockView

java非阻塞NIO和阻塞IO的更多相关文章

  1. JAVA中的NIO (New IO)

    简介 标准的IO是基于字节流和字符流进行操作的,而JAVA中的NIO是基于Channel和Buffer进行操作的. 传统IO graph TB; 字节流 --> InputStream; 字节流 ...

  2. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  3. JAVA阻塞(IO)和非阻塞(NIO)

    查看这篇文章,了解更多关于Java的阻塞和非阻塞替代创建套接字的信息. 套接字使用TCP / IP传输协议,是两台主机之间的最后一块网络通信. 您通常不必处理它们,因为它们之上构建了协议,如HTTP或 ...

  4. java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO

    原文地址: IO读写的基础原理 大家知道,用户程序进行IO的读写,依赖于底层的IO读写,基本上会用到底层的read&write两大系统调用.在不同的操作系统中,IO读写的系统调用的名称可能不完 ...

  5. JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞

    在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...

  6. IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)

    同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...

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

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

  8. NIO 之阻塞IO和非阻塞IO(转载)

    阻塞模式 IO 我们已经介绍过使用 Java NIO 包组成一个简单的客户端-服务端网络通讯所需要的 ServerSocketChannel.SocketChannel 和 Buffer,我们这里整合 ...

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

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

随机推荐

  1. JAVA8 中 LocalDateTime的使用小栗子

    LocalDate givenDate = LocalDate.parse("2019-04-23",DateTimeFormatter.ofPattern("yyyy- ...

  2. 关于MapReduce二次排序的一点解答

    上一篇博客说明了怎么自定义Key,而且用了二次排序的例子来做测试,但没有详细的说明二次排序,这一篇说详细的说明二次排序,为了说明曾经一个思想的误区,特地做了一个3个字段的二次排序来说明.后面称其为“三 ...

  3. git本地分支与远程分支

    github上已经有master分支 和dev分支 在本地 git checkout -b dev 新建并切换到本地dev分支 git pull origin dev 本地分支与远程分支相关联 在本地 ...

  4. 再谈javascriptjs原型与原型链及继承相关问题

    什么是原型语言 只有对象,没有类;对象继承对象,而不是类继承类. “原型对象”是核心概念.原型对象是新对象的模板,它将自身的属性共享给新对象.一个对象不但可以享有自己创建时和运行时定义的属性,而且可以 ...

  5. Django框架详细介绍---Form表单

    一.概述 在HTML页面中,利用form表单向后端提交数据时,需要编写input等输入标签并用form标签包裹起来,与此同时,在很多应用场景之下需要对用户输入的数据校验,例如注册登录页面中,校验用户注 ...

  6. Delphi获取本机所有的IP

    安装Indy uses  IdStackWindows; var Isw:TIdStackWindows; slist:TStringList; begin Isw:=TIdStackWindows. ...

  7. 项目遇到的小问题(关于vue-cli中js点击事件不起作用和iconfont图片下载页面css样式乱的解答)

     第一个:关于vue-cli中js点击事件不起作用 在vue的methods方法queryBtnFun()中拼接html和click操作事件的时候,发现点击事件一起未起作用: 后来发现是DOM执行顺序 ...

  8. spring源码解析1--spring整体架构

    一.Spring整体架构图 关于Spring的基本介绍就不再赘述了,先展示Spring框架的整体架构图如下示: 二.Spring结构介绍 Spring主要分为Core Container.Test.D ...

  9. 哨兵2 NDVI

    shp从国外网站下载的,不是很准确了 数据:COPERNICUS/S2 交流合作请联系:ab000c@163.com

  10. React 列表页面传递参数

    React 列表进入详情页面 首先安装 react-router-dom (4.0) npm/yarn install react-router-dom 路由跳转配置 列表 父组件 this.prop ...