java非阻塞NIO和阻塞IO
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;
importjava.nio.file.Paths;
importjava.nio.file.StandardOpenOption;
import org.junit.Test;
publicclass TestBlockingNIO{
//客户端
@Test
public void client() throws IOException{
//1、获取通道(open这种方法是jdk1.7之后才引入的)
SocketChannel socketChannel = SocketChannel.open(newInetSocketAddress("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();
//另一种方法就是把这个线程切换成非阻塞模式
//接收服务端反馈
intlen =0;
while((len = socketChannel.read(buf)) !=-1){
buf.flip();
System.out.println(newString(buf.array(),0,len));
}
//4、关闭通道
inFileChannel.close();
socketChannel.close();
}
//服务端
@Test
public void server() throws IOException{
//1、获取端口
ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
//2、绑定连接
serverSocketChannel.bind(newInetSocketAddress(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的更多相关文章
- JAVA中的NIO (New IO)
简介 标准的IO是基于字节流和字符流进行操作的,而JAVA中的NIO是基于Channel和Buffer进行操作的. 传统IO graph TB; 字节流 --> InputStream; 字节流 ...
- Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO
Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...
- JAVA阻塞(IO)和非阻塞(NIO)
查看这篇文章,了解更多关于Java的阻塞和非阻塞替代创建套接字的信息. 套接字使用TCP / IP传输协议,是两台主机之间的最后一块网络通信. 您通常不必处理它们,因为它们之上构建了协议,如HTTP或 ...
- java的高并发IO原理,阻塞BIO同步非阻塞NIO,异步非阻塞AIO
原文地址: IO读写的基础原理 大家知道,用户程序进行IO的读写,依赖于底层的IO读写,基本上会用到底层的read&write两大系统调用.在不同的操作系统中,IO读写的系统调用的名称可能不完 ...
- JAVA 中BIO,NIO,AIO的理解以及 同步 异步 阻塞 非阻塞
在高性能的IO体系设计中,有几个名词概念常常会使我们感到迷惑不解.具体如下: 序号 问题 1 什么是同步? 2 什么是异步? 3 什么是阻塞? 4 什么是非阻塞? 5 什么是同步阻塞? 6 什么是同步 ...
- IO通信模型(二)同步非阻塞模式NIO(NonBlocking IO)
同步非阻塞模式(NonBlocking IO) 在非阻塞模式中,发出Socket的accept()和read()操作时,如果内核中的数据还没有准备好,那么它并不会阻塞用户进程,而是立刻返回一个信息.也 ...
- NIO之阻塞IO与非阻塞IO(包含Selector使用)
阻塞IO 传统的 IO 流都是阻塞式的. 也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务. 因此,在完成网络通信 ...
- NIO 之阻塞IO和非阻塞IO(转载)
阻塞模式 IO 我们已经介绍过使用 Java NIO 包组成一个简单的客户端-服务端网络通讯所需要的 ServerSocketChannel.SocketChannel 和 Buffer,我们这里整合 ...
- 【死磕NIO】— 阻塞IO,非阻塞IO,IO复用,信号驱动IO,异步IO,这你真的分的清楚吗?
通过上篇文章([死磕NIO]- 阻塞.非阻塞.同步.异步,傻傻分不清楚),我想你应该能够区分了什么是阻塞.非阻塞.异步.非异步了,这篇文章我们来彻底弄清楚什么是阻塞IO,非阻塞IO,IO复用,信号驱动 ...
随机推荐
- MATLAB矩阵运算
1. 矩阵的加减乘除和(共轭)转置 (1) 矩阵的加法和减法 如果矩阵A和B有相同的维度(行数和列数都相等),则可以定义它们的和A+B以及它们的差A-B,得到一个与A和B同维度的矩阵C,其中Cij=A ...
- sublime There are no packages available for installation 问题的解决办法
这个是因为IPv6的原因, 因此我们需要修改我们的 /etc/hosts文件. 第一步: 执行: nm-tool 获取DNS的信息 例如: DNS: 192.168.1.11 第二步: 在/etc/h ...
- 关于MySQL数据库的安装和卸载
0.官网下载 https://www.mysql.com/ 选择需要的版本下载 两种安装方式,选择需要的安装包 下载 1.MySQL 5.6 for Windows 解压缩版配置安装 https:// ...
- 在windows+eclipse+git遇到的未修改文件被标记为已修改的问题
最近遇到2个具体的问题: 1.我们有个工程里面有几个外部jar包,这几个jar包经常会更新,更新的时候如果是在eclipse中执行的,由于windows文件机制,所以会报错无法覆盖这几个jar包.虽然 ...
- c# WebApi之接口返回类型详解
c# WebApi之接口返回类型详解 https://blog.csdn.net/lwpoor123/article/details/78644998
- ceph运维常用指令
一.集群 1.启动一个ceph 进程 启动mon进程 service ceph start mon.node1 启动msd进程 service ceph start mds.node1 启动osd进 ...
- .NET 常用ORM之NHibernate
NHibernate做.Net应该都不陌生,今天我们就算是温故下这个技术,概念性的东西就不说了,这次主要说本人在实际使用的遇到的问题,比较费解现在就当是记录下,避免以后再犯.本次主要使用的情况是1对N ...
- 用java实现操作两个数据库的数据
1.首先需要在jdbc的配置文件里面配置两个数据库的连接 数据库1的配置 driverClassName=com.mysql.jdbc.Driverurl=jdbc:mysql://地址:3306/数 ...
- MTK-TP(电阻屏校准程序ts_lib移植)
现今的项目中已经很少有使用电阻TP,但总有些奇怪的需求.如果项目中遇到需要校准电阻屏如何保证较快且较稳的调试TP呢.这里介绍使用ts_lib库来进行调试. 当然也可以使用一些常见的校准算法,采集5点, ...
- Hi3516A开发--接触(转)
Hi3516A开发--接触