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. OO第一单元总结(表达式求导)

    写在前边:第一次接触面向对象语言,编程思想仍然不可避免的有以前面向过程的影子.从第一次作业的完全面向过程,到第二次学会剥离各个类互不影响到第三次作业的先构思面向对象的基本程序架构再编程.虽然程序有些地 ...

  2. 后台发送get请求

    第一步:编写Controller,让后台去请求接口 package controller; import java.util.List; import org.springframework.bean ...

  3. https://blog.csdn.net/uftjtt/article/details/79044186

    https://blog.csdn.net/uftjtt/article/details/79044186

  4. ajax请求网络api

    不啰嗦,直接上代码: 1.在浏览器输入网址:http://api.asilu.com/weather/?callback=getname&city=深圳 你会看到如下结果:他返回的是json数 ...

  5. Windbg程序调试系列4-Live Debugging

    上篇博文中给大家分享了使用Windbg分析线程阻塞问题: Windbg程序调试系列3-线程阻塞问题 本篇中我们继续,跟大家分享附加进程实时调试-Live Debugging. 先说一下使用Windbg ...

  6. ubuntu+anaconda+mxnet环境配置

    为了insightface和mxnet较劲的一天 mxnet环境: 官网下载pyhton2.7版本的anaconda,随便找个安装教程 sh Anacondaxxxx.sh #一路默认即可,第二个回车 ...

  7. spring-boot 2.1.2.RELEASE bug

    不打印映射地址日志: 改用 2.0.5 RELEASE 即可

  8. Upload a file with $.ajax to AWS S3 with a pre-signed url

    转载自:https://gist.github.com/guumaster/9f18204aca2bd6c71a24 生成预签名的Demo文档:https://docs.aws.amazon.com/ ...

  9. parse

    import Parse from 'parse'; import { AsyncStorage } from 'react-native'; // 创建新的子类 var GameScore = Pa ...

  10. 利用Python计算π的值,并显示进度条

    利用Python计算π的值,并显示进度条  第一步:下载tqdm 第二步;编写代码 from math import * from tqdm import tqdm from time import ...