一. 什么是阻塞?
阻塞(Block)这个概念。当进程调用一个阻塞的系统函数时,该进程被置于睡眠(Sleep)状态,这时内核调度其它进程运行,直到该进程等待的事件发生了(比如网络上接收到数据包,或者调用sleep指定的睡眠时间到了)它才有可能继续运行。
我自己是这样理解(同步/异步、阻塞/非阻塞)的:
所谓同步就是当一个进程发起一个函数(任务)调用的时候,一直会到函数(任务)完成。进程继续往下执行。而异步这不会这样,异步情况下是当一个进程发起一个函数(任务)调用的时候,不会等函数返回,而是继续往下执行当,函数返回的时候通过状态、通知、事件。等方式通知进程任务完成。
而阻塞和非阻塞的概念相对明了多了。阻塞是当请求不能满足的时候就试进程挂起,非阻塞则是直接返回。
二.NIO包
java.nio包是Java在1.4之后增加的,用来提高I/O操作的效率。在nio包中主要包括以下几个类或接口:
* Buffer:缓冲区,用来临时存放输入或输出数据。
* Charset:用来把Unicode字符编码和其它字符编码互转。
* Channel:数据传输通道,用来把Buffer中的数据写入到数据源,或者把数据源中的数据读入到Buffer。
* Selector:用来支持异步I/O操作,也叫非阻塞I/O操作。
nio包中主要通过下面两个方面来提高I/O操作效率:
* 通过Buffer和Channel来提高I/O操作的速度。
* 通过Selector来支持非阻塞I/O操作。
三. 代码示例(文件读写 & socket通讯)
以下是 BIO,和NIO的 文件读写、socket通讯,大家可以对比下有什么不一样
BIO:
public class FileIODemo {
public static void main(String[] args) {
//获取文件
File fileRead = new File("fileIORead.txt");
File fileWrite = new File("fileIOWrite.txt");
//字节流
try {
FileInputStream input=new FileInputStream(fileRead);
FileOutputStream out=new FileOutputStream(fileWrite);
//缓冲数组
byte[] buffer=new byte[10];
int i=0;
while(input.read(buffer)!=-1){
System.out.println("i:"+i++);
out.write(buffer);
}
input.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO:
public class FileNIODemo {
public static void main(String[] args) {
//获取文件
File fileRead = new File("fileIORead.txt");
File fileWrite = new File("fileIOWrite.txt");
try {
FileInputStream input = new FileInputStream(fileRead);
FileOutputStream out=new FileOutputStream(fileWrite);
FileChannel inputChannel= input.getChannel();
FileChannel outputChannel=out.getChannel();
ByteBuffer buffer=ByteBuffer.allocate(10);
int i=0;
while(true){
buffer.clear();
int res=inputChannel.read(buffer);
if(res==-1){
break;
}
buffer.flip();
outputChannel.write(buffer);
System.out.println("i:"+i++);
}
inputChannel.close();
input.close();
outputChannel.close();
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
====================================================================================================================================
咱们再来看看 socket;
BIO:
//客户端
public class ClientIODemo {
public static void main(String[] args) {
try {
Socket socket=new Socket("127.0.0.1",12345);
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
//客户端发送消息
String message="[client]: send a message:发送消息!";
byte[] context=message.getBytes();
out.write(context);
out.flush();
System.out.println(message);
//客户端接受消息
StringBuilder feedback = new StringBuilder();
byte[] buffer=new byte[1000];
in.read(buffer);
feedback.append(new String(buffer,Charset.defaultCharset()));
System.out.println("[client]: receive a message:"+feedback.toString());
in.close();
out.close();
socket.close();
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//服务端
public class ServerIODemo {
public static void main(String[] args) {
try {
ServerSocket server=new ServerSocket(12345);
while(true){
Socket socket = server.accept();//阻塞
InputStream in=socket.getInputStream();
OutputStream out=socket.getOutputStream();
StringBuilder message=new StringBuilder();
byte[] buffer=new byte[10];
int i=0;
while(true){
i++;
in.read(buffer); //当发现没有值read的时候,就阻塞住了
message.append(new String(buffer,Charset.defaultCharset()));
if(i>10){
break;
}
}
System.out.println("[server]:"+message);
String messages="[server]: send a message:发送消息!";
byte[] context=messages.getBytes();
out.write(context);
out.flush();
in.close();
out.close();
socket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
NIO:
//客户端
public class ClientNIODemo {
public static void main(String[] args) {
try {
//创建客户端通道
SocketChannel client=SocketChannel.open();
Selector selector= Selector.open();
//设置成非阻塞
client.configureBlocking(false);
client.connect(new InetSocketAddress("127.0.0.1", 12345));
//注册监听Connect
client.register(selector, SelectionKey.OP_CONNECT);
boolean complate=true;
while(complate){
try {
selector.select();
} catch (IOException e) {
e.printStackTrace();
break;
}
Set<SelectionKey> keys= selector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
while(iterator.hasNext()){
SelectionKey key=iterator.next();
iterator.remove();
if(key.isConnectable()&&client.finishConnect()){
System.out.println("=============connectable");
key.interestOps(SelectionKey.OP_WRITE);
}
if(key.isReadable()){
System.out.println("=============readable");
SocketChannel channel=(SocketChannel) key.channel();
ByteBuffer buffer=ByteBuffer.allocate(10);
StringBuilder feedback=new StringBuilder();
while(true){
int res=channel.read(buffer);
if(res==-1||res==0){
break;
}else if(res>0){
buffer.flip();
feedback.append(new String(buffer.array(),Charset.defaultCharset()));
buffer.clear();
}
}
System.out.println("[client]:"+feedback);
complate=false;
}
if(key.isWritable()){
System.out.println("=============writeable");
SocketChannel channel=(SocketChannel) key.channel();
ByteBuffer buffer=ByteBuffer.allocate(100);
String message="send a message:客户端发消息了!";
byte[] context=message.getBytes();
buffer.put(context);
buffer.flip();
channel.write(buffer);
key.interestOps(SelectionKey.OP_READ);
}
}
}
client.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
//服务端
public class ServerNIODemo {
public static void main(String[] args) {
ServerSocketChannel serverChannel;
Selector selector;
try{
//服务端的准备
serverChannel= ServerSocketChannel.open();
ServerSocket serverSocket=serverChannel.socket();
serverSocket.bind(new InetSocketAddress(12345));
serverChannel.configureBlocking(false);
selector=Selector.open();
serverChannel.register(selector, SelectionKey.OP_ACCEPT);
} catch (IOException e){
e.printStackTrace();
return;
}
while(true){
try {
selector.select();
} catch (IOException e) {
e.printStackTrace();
break;
}
Set<SelectionKey> readKeys = selector.selectedKeys();
Iterator<SelectionKey> iterator = readKeys.iterator();
while(iterator.hasNext()){
SelectionKey key=iterator.next();
iterator.remove();
try {
if(key.isAcceptable()){
System.out.println("=============accept");
ServerSocketChannel server = (ServerSocketChannel) key.channel();
//接受客户端的请求
SocketChannel client=server.accept();
//客户端 服务端 全都设置为 非阻塞
client.configureBlocking(false);
client.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocate(100));
}
if(key.isReadable()){
System.out.println("=============read");
SocketChannel client=(SocketChannel) key.channel();
ByteBuffer buffer=ByteBuffer.allocate(10);
WritableByteChannel out = Channels.newChannel(System.out);
while(true){
int res=client.read(buffer);
if(res==-1||res==0){
break;
}else if(res>0){
buffer.flip();
out.write(buffer);
buffer.clear();
}
}
System.out.println();
key.interestOps(SelectionKey.OP_WRITE);
}
if(key.isWritable()){
System.out.println("=============write");
SocketChannel client=(SocketChannel) key.channel();
ByteBuffer buffer=(ByteBuffer) key.attachment();
String message="send a message:服务端发消息了!";
byte[] context=message.getBytes();
buffer.clear();
buffer.put(context);
buffer.flip();
client.write(buffer);
key.cancel();
System.out.println("=============send");
try {
//取消键后仍可以得到键的通道
key.channel().close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
从以上2个列子可以可以看出:
对于BIO如果服务端读取客户端发来的信息,如果用while(true)进行循环读取,读到-1时截止,那么必须要将客服端进行关闭,否则客户端和服务端就都等待对方进行发送消息,或者关闭。也就卡死在那了。
对于NIO来说,不管服务端or客户端,只要没有数据读取直接进行返回,返回为0,如果关闭则返回-1。从而可以进行其他的逻辑。 这也就是非阻塞的概念。
对比发现,NIO多了 Channel 和 Buffer 这2个重要的类!后续我们将着重进行介绍 “通道”“缓存区”
分享到:
相关推荐
NULL 博文链接:https://1358440610-qq-com.iteye.com/blog/2117280
本项目示例基于spring boot 最新版本(2.1.9)实现,Spring Boot、Spring Cloud 学习示例,将持续更新…… 在基于Spring Boot、Spring Cloud 分布微服务开发过程中,根据实际项目环境,需要选择、集成符合项目...
NULL 博文链接:https://1358440610-qq-com.iteye.com/blog/2115715
赠送jar包:httpcore-nio-4.4.6.jar 赠送原API文档:httpcore-nio-4.4.6-javadoc.jar 赠送源代码:httpcore-nio-4.4.6-sources.jar 包含翻译后的API文档:httpcore-nio-4.4.6-javadoc-API文档-中文(简体)版.zip ...
Java I/O学习笔记: 磁盘操作 字节操作 字符操作 对象操作 网络操作 NIO & AIO Java I/O Java是一种面向对象的编程语言,由Sun Microsystems于1995年推出。它是一种跨平台的语言,意味着可以在不同的操作系统上运行...
赠送jar包:httpcore-nio-4.4.15.jar 赠送原API文档:httpcore-nio-4.4.15-javadoc.jar 赠送源代码:httpcore-nio-4.4.15-sources.jar 包含翻译后的API文档:httpcore-nio-4.4.15-javadoc-API文档-中文(简体)版....
以浸渍-焙烧法制备NiO/Al2O3型催化剂.采用该催化剂微波热解低变质煤,探讨了热解产生的气体组成、液态油品成分特点及固态残渣的形貌与负载催化剂制备条件的相互关系,考察了负载NiO的工艺条件如浸渍方式、焙烧时间和...
组成对La2NiO4+δ-La0.6Sr0.4Co0.2Fe0.8O3-δ复合阴极材料导电性能与热膨胀性能的影响,石海,常贵阳,本文选择La2NiO4+δ与La0.6Sr0.4Co0.2Fe0.8O3-δ为组元,设计并制备出(100-x)wt.%La2NiO4+δ+xwt.% La0.6Sr0.4...
java学习笔记1(java io/nio)设计模式
赠送jar包:xnio-nio-3.8.4.Final.jar; 赠送原API文档:xnio-nio-3.8.4.Final-javadoc.jar; 赠送源代码:xnio-nio-3.8.4.Final-sources.jar; 赠送Maven依赖信息文件:xnio-nio-3.8.4.Final.pom; 包含翻译后的API...
赠送jar包:httpcore-nio-4.4.10.jar; 赠送原API文档:httpcore-nio-4.4.10-javadoc.jar; 赠送源代码:httpcore-nio-4.4.10-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.10.pom; 包含翻译后的API文档...
赠送jar包:httpcore-nio-4.4.15.jar 赠送原API文档:httpcore-nio-4.4.15-javadoc.jar 赠送源代码:httpcore-nio-4.4.15-sources.jar 包含翻译后的API文档:httpcore-nio-4.4.15-javadoc-API文档-中文(简体)-...
赠送jar包:httpcore-nio-4.4.10.jar; 赠送原API文档:httpcore-nio-4.4.10-javadoc.jar; 赠送源代码:httpcore-nio-4.4.10-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.10.pom; 包含翻译后的API文档...
赠送jar包:httpcore-nio-4.4.5.jar; 赠送原API文档:httpcore-nio-4.4.5-javadoc.jar; 赠送源代码:httpcore-nio-4.4.5-sources.jar; 赠送Maven依赖信息文件:httpcore-nio-4.4.5.pom; 包含翻译后的API文档:...
java.nio (NIO stands for non-blocking I/O) is a collection of Java programming language APIs that offer features for intensive I/O operations. It was introduced with the J2SE 1.4 release of Java by ...
Java-NIO非阻塞服务器示例.docx
Nio学习笔记
Java I/O, NIO, and NIO.2 is a power-packed book that accelerates your mastery of Java's various I/O APIs. In this book, you'll learn about classic I/O APIs (File, RandomAccessFile, the stream classes ...
经过我2个月的深入学习,反复修改测试,开发出一个已经能稳定使用的端口代理程序,源代码没有应用所有nio知识,但比较全面的覆盖了nio编程中需要注意的几点,如果有什么问题,可以联系我:gypzfabc@126.com