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. MongoDB3.2新特性之部分索引

    官方介绍:https://docs.mongodb.org/manual/core/index-partial/ mongodb3.2支持对某个集合的部分数据创建索引.如给年龄大于十八岁的数据创建索引 ...

  2. c# 调用浏览器打开网址并全屏

    关键性参数 Google Chrome浏览器 Process process = Process.Start("chrome.exe", " --kiosk " ...

  3. VS 2017 激活码

    最近逐渐抛弃了 VS2015  更新迭代到2017版本安装流程不必说激活码双手奉上 Enterprise: NJVYC-BMHX2-G77MM-4XJMR-6Q8QF Professional: KB ...

  4. 编年史:OI测试

    2019.4.18 t1:给出不定方程ax+by+c=0,求x在x1~x2并且y在y1~y2时的解个数.考场上想的是一个扩欧板子敲下去,然后构造出x>=x1的最小解,同时得出y,然后通过通项来枚 ...

  5. windows----------火狐浏览器访问所有https网站都显示链接不安全解决办法

    1.如有以下情况,点右边的“高级”,看看自己的错误码是否为SEC_ERROR_UNKNOWN_ISSUER 2.在地址栏键入"about:config" 点击“我了解此风险” 3. ...

  6. django请求接收及文件上传

    在写后端交互页面的时候常常会遇到接收来自前端页面请求的情况,例如 在写注册页面的时候,会提交一些页面信息,这时需要分三种情况讨论 第一种,接收单项信息: v = request.POST.getlis ...

  7. eclipse配置tomcat添加外部项目

    在eclipse中配置tomcat,添加外部项目. 添加外部项目 然后直接启动服务器,服务器里面不能添加项目.

  8. 5+移动App

    1.5+ App开发入门指南 https://www.cnblogs.com/tuyile006/p/5395909.html 2.5+ App开发Native.js入门指南 http://ask.d ...

  9. 架构设计---soa与msa的概念(转)

    https://blog.csdn.net/qq_15001229/article/details/79535037

  10. luogu P1003 铺地毯

    水题 #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; t ...