转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7794151.html

  前面讲到:Java IO编程全解(四)——NIO编程

  NIO2.0引入了新的异步通道的概念,并提供了异步文件通道和异步套接字通道的实现。异步通道提供两种方式获取操作结果。

  • 通过java.util.concurrent.Future类来表示异步操作的结果;
  • 在执行异步操作的时候传入一个java.nio.channels。

  CompletionHandler接口的实现类作为操作完成的回调。

  NIO2.0的异步套接字通道是真正的异步非阻塞I/O,它对UNIX网络编程中的事件驱动I/O(AIO),它不需要通过多路复用器(Selector)对注册的通道进行轮询操作即可实现异步读写,从而简化了NIO的编程模型。

  下面通过代码来熟悉NIO2.0 AIO的相关类库,仍旧以时间服务器为例程进行讲解。

1.AIO创建的TimeServer源码分析

package joanna.yan.aio;public class TimeServer {public static void main(String[] args) {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默认值
            }}AsyncTimeServerHandler timeServer=new AsyncTimeServerHandler(port);new Thread(timeServer,"AIO-AsyncTimeServerHandler-001").start();}
}

package joanna.yan.aio;import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.util.concurrent.CountDownLatch;public class AsyncTimeServerHandler implements Runnable{private int port;CountDownLatch latch;AsynchronousServerSocketChannel asynchronousServerSocketChannel;public AsyncTimeServerHandler(int port){this.port=port;try {//创建一个异步的服务端通道AsynchronousServerSocketChannelasynchronousServerSocketChannel=AsynchronousServerSocketChannel.open();asynchronousServerSocketChannel.bind(new InetSocketAddress(port));System.out.println("The time server is start in port: "+port);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {/**初始化CountDownLatch对象。 *它的作用是,在完成一组正在执行的操作之前,允许当前的线程一直阻塞。*在本例中,我们让线程在此阻塞,防止服务器执行完成退出。*在实际项目应用中,不需要启动独立的线程来处理AsynchronousServerSocketChannel,这里仅仅是个demo演示。*/latch=new CountDownLatch(1);doAccept();try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}}/*** 接收客户端的连接。* 由于这里是异步操作。我们可以传递一个CompletionHandler<AsynchronousSocketChannel,? super A>类型* 的handler实例接收accept操作成功的通知消息*/public void doAccept() {asynchronousServerSocketChannel.accept(this, new AcceptCompletionHandler());}
}

package joanna.yan.aio;import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
/*** 接收accept操作成功的通知消息* @author Administrator**/
public class AcceptCompletionHandler implements CompletionHandler<AsynchronousSocketChannel,AsyncTimeServerHandler>{@Overridepublic void completed(AsynchronousSocketChannel result,AsyncTimeServerHandler attachment) {/** 疑惑:既然已经接收客户端成功了,为什么还要再次调用accept方法呢?* 原因:当我们调用AsynchronousServerSocketChannel的accept方法后,如果有新的客户端连接接入,* 系统将回调我们传入的CompletionHandler实例的completed方法,表示新的客户端已经接入成功,* 因为一个AsynchronousServerSocketChannel可以接收成千上万个客户端,所以我们需要继续调用它的accep方法,* 接收其他的客户端连接,最终形成一个循环。* 每当接收一个客户读连接成功之后,再异步接收新的客户端连接。*/attachment.asynchronousServerSocketChannel.accept(attachment, this);ByteBuffer buffer=ByteBuffer.allocate(1024);/** 参数一:接收缓冲区,用于从异步Channel中读取数据包;* 参数二:异步Channel携带的附件,通知回调的时候作为入参使用;* 参数三:接收通知回调的业务handler*/result.read(buffer, buffer, new ReadCompletionHandler(result));}@Overridepublic void failed(Throwable exc, AsyncTimeServerHandler attachment) {exc.printStackTrace();attachment.latch.countDown();}
}

package joanna.yan.aio;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.Date;
/*** 主要用于读取半包消息和发送应答。* 本例不对半包读写进行具体说明,在后面的Netty半包处理中会介绍。* @author Administrator**/
public class ReadCompletionHandler implements CompletionHandler<Integer, ByteBuffer>{private AsynchronousSocketChannel channel;public ReadCompletionHandler(AsynchronousSocketChannel channel){if(this.channel==null){this.channel=channel;}}@Overridepublic void completed(Integer result, ByteBuffer attachment) {//为后续从缓冲区读取数据做准备
        attachment.flip();byte[] body=new byte[attachment.remaining()];attachment.get(body);try {String req=new String(body, "UTF-8");System.out.println("The time server receive order : "+req);String currentTime="QUERY TIME ORDER".equalsIgnoreCase(req) ? new Date(System.currentTimeMillis()).toString() : "BAD ORDER";doWrite(currentTime);} catch (UnsupportedEncodingException e) {e.printStackTrace();}}/*** 发生异常的时候调用。* 对异常Throwable进行判断,如果是I/O异常,就关闭链路,释放资源;* 如果是其它异常,按照业务自己的逻辑进行处理。* 本例作为简单demo,没有对异常进行分类判断,只要发生了读写异常,就关闭链路,释放资源。*/@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {try {this.channel.close();} catch (IOException e) {e.printStackTrace();}}private void doWrite(String currentTime) {if(currentTime!=null&&currentTime.trim().length()>0){byte[] bytes=currentTime.getBytes();ByteBuffer writeBuffer=ByteBuffer.allocate(bytes.length);writeBuffer.put(bytes);writeBuffer.flip();channel.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {@Overridepublic void completed(Integer result, ByteBuffer buffer) {//如果没有发送完成,继续发送if(buffer.hasRemaining()){channel.write(buffer, buffer, this);}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {try {channel.close();} catch (IOException e) {//ingnore on close
                    }}});}}
}

2.AIO创建的TimeClient源码分析

package joanna.yan.aio;public class TimeClient {public static void main(String[] args) {int port=9090;if(args!=null&&args.length>0){try {port=Integer.valueOf(args[0]);} catch (Exception e) {// 采用默认值
            }}/** 通过一个独立的I/O线程创建异步时间服务器客户端handler。* 在实际项目中,我们不需要独立的线程创建异步连接对象,因为底层都是通过JDK的系统回调实现的。*/new Thread(new AsyncTimeClientHandler("127.0.0.1", port),"AIO-AsyncTimeClientHandle-001").start();/** 需要指出的是,正如之前的NIO例程,我们并没有完整的处理网络的半包读写,在对例程进行功能测试的是还没有问题,* 但是,如果对代码稍加改造,进行压力或者性能测试,就会发现输出结果存在问题。* 这里只集中将NIO的入门知识,后面会详细讲到半包读写*/}
}

package joanna.yan.aio;import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;public class AsyncTimeClientHandler implements CompletionHandler<Void, AsyncTimeClientHandler>,Runnable{private AsynchronousSocketChannel client;private String host;private int port;private CountDownLatch latch;public AsyncTimeClientHandler(String host,int port){this.host=host;this.port=port;try {client=AsynchronousSocketChannel.open();} catch (IOException e) {e.printStackTrace();}}@Overridepublic void completed(Void result, AsyncTimeClientHandler attachment) {byte[] req="QUERY TIME ORDER".getBytes();ByteBuffer writeBuffer=ByteBuffer.allocate(req.length);writeBuffer.put(req);writeBuffer.flip();client.write(writeBuffer, writeBuffer, new CompletionHandler<Integer, ByteBuffer>() {//用于写操作完成后的回调
@Overridepublic void completed(Integer result, ByteBuffer buffer) {if(buffer.hasRemaining()){client.write(buffer, buffer, this);}else{ByteBuffer readBuffer=ByteBuffer.allocate(1024);client.read(readBuffer, readBuffer, new CompletionHandler<Integer, ByteBuffer>(){//当读取完成被JDK回调时,构造应答消息。
@Overridepublic void completed(Integer result,ByteBuffer buffer) {buffer.flip();byte[] bytes=new byte[buffer.remaining()];buffer.get(bytes);String body;try {body=new String(bytes, "UTF-8");System.out.println("Now is : "+body);latch.countDown();} catch (UnsupportedEncodingException e) {e.printStackTrace();}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {try {client.close();//让AsyncTimeClientHandler线程执行完毕,客户端退出执行
                                latch.countDown();} catch (IOException e) {//ingnore on close
                            }}   });}}@Overridepublic void failed(Throwable exc, ByteBuffer attachment) {try {client.close();latch.countDown();} catch (IOException e) {//ingnore on close
                }}});}@Overridepublic void failed(Throwable exc, AsyncTimeClientHandler attachment) {exc.printStackTrace();try {client.close();latch.countDown();} catch (IOException e) {//ingnore on close
        }}@Overridepublic void run() {//创建CountDownLatch进行等待,防止异步操作没有执行完成线程就退出。latch=new CountDownLatch(1);/** 参数二:AsynchronousSocketChannel的附件,用于回调通知时作为入参被传递,调用者可以自定义* 参数三:异步参数回调通知接口,由调用者实现。*/client.connect(new InetSocketAddress(host, port), this, this);try {latch.await();} catch (InterruptedException e) {e.printStackTrace();}try {client.close();} catch (IOException e) {e.printStackTrace();}}
}

  异步SocketChannel是被动执行对象,我们不需要像NIO编程那样创建一个独立I/O线程来处理读写操作。对于AsynchronousServerSocketChannel和 AsynchronousSocketChannel,它们都由JDK底层的线程池负责回调并驱动读写操作。正因为如此,基于NIO2.0新的异步非阻塞Channel进行编程比NIO编程更为简单。

  后面,我们将对前面讲到的4种I/O进行概念澄清和比较,让大家从整体上掌握这些I/O模型的差异。以便在未来的工作中能够根据产品的实际情况选择合适的I/O模型。

Java IO编程全解(六)——4种I/O的对比与选型

如果此文对您有帮助,微信打赏我一下吧~

Java IO编程全解(五)——AIO编程相关推荐

  1. Java IO编程全解(六)——4种I/O的对比与选型

    转载请注明出处:http://www.cnblogs.com/Joanna-Yan/p/7804185.html 前面讲到:Java IO编程全解(五)--AIO编程 为了防止由于对一些技术概念和术语 ...

  2. 全方位地介绍JavaScript开发中的各个主题《JavaScript编程全解》(好书分享更新中)

    JavaScript编程全解 作者: [日]井上诚一郎 / [日]土江拓郎 / [日]滨边将太 出版社: 人民邮电出版社 译者: 陈筱烟 内容简介  · · · · · · 本书全方位地介绍了Java ...

  3. python基础系列教程——python面向对象编程全解

    全栈工程师开发手册 (作者:栾鹏) python教程全解 python面向对象编程全解. 面向对象技术简介 一个类占有一个独立的空间,类中的属性叫做类变量,类中的函数,叫做类的方法. 类(Class) ...

  4. java io流详解_一文带你看懂JAVA IO流,史上最全面的IO教学啦

    一.IO流是什么 惯例引用百科的回答流是一种抽象概念,它代表了数据的无结构化传递.按照流的方式进行输入输出,数据被当成无结构的字节序或字符序列.从流中取得数据的操作称为提取操作,而向流中添加数据的操作 ...

  5. #《JAVA程序设计》 20155214 实验五 网络编程与安全

    <JAVA程序设计> 20155214 实验五 网络编程与安全 实验内容 掌握Socket程序的编写: 掌握密码技术的使用: 设计安全传输系统. 实验要求 要求一 结对实现中缀表达式转后缀 ...

  6. Java IO操作详解

    在Java编程中,IO(输入输出)是重要的组成部分,Java应用常常需要从外界输入数据或者把数据输出到外界. Java IO的核心用一句话概括:抽象类或接口之中的抽象方法会根据实例化子类的不同,会完成 ...

  7. Java数据类型转换全解

    Java数据类型转换全解 我们知道Java语言是典型的支持面向对象的程序语言,但考虑到有些基本Java数据类型的结构简单,占内存小且存取速度快等优点,Java依然提供了对这些非面向对象的简单Java数 ...

  8. 网络编程全解(Java)

    网络编程 1.1 概述 计算机网络: 计算网络是指将地理位置不同的具有独立功能的多台计算机及其外部设备,通过通信线路连接起来,在网络操作系统,网络管理软件及网络通信协议的管理和协调下,实现资源共享和信 ...

  9. java 网络实验_Java实验五网络编程与安全

    实验五 网络编程与安全 实验准备 活动一 两人一组结对编程: 0. 参考http://www.cnblogs.com/rocedu/p/6766748.html#SECDSA 1. 结对实现中缀表达式 ...

最新文章

  1. 【Linux多线程】三个经典同步问题
  2. python memory usage_Python Pandas Index.memory_usage()用法及代码示例
  3. windows mobile5.0之“hello world”
  4. [论文阅读] (06) 万字详解什么是生成对抗网络GAN?经典论文及案例普及
  5. Oracle中的正则表达式(REPLACE 和REGEXP_REPLACE)---转载自http://database.51cto.com/art/201009/228270.htm...
  6. 揭开Java 泛型类型擦除神秘面纱
  7. java中的规范是什么意思_Java中的异常规范有什么好处?
  8. Mysql索引是有序的吗_mysql组合索引的有序性转
  9. LeetCode自我总结(对链表进行插入排序)
  10. python 接口测试 如何写配置文件_python接口自动化之ConfigParser配置文件的使用详解...
  11. 如何获取git diff文件,并将其应用于作为同一存储库副本的本地分支?
  12. ADO.NET编程(4)根据条件查询DataTable的值
  13. 10以内逆向运算题_加减法启蒙系列 | 实战篇二(10以内减法)
  14. 121 Python程序中的线程操作-线程定时器
  15. 一个简单的WEB网页制作作业——黑色的山河旅行社网站(5个页面)HTML+CSS+JavaScript
  16. scala机器学习实战(三) 保险数据预测分析(LR算法详解)
  17. 海明贴近度matlab,Matlab学习系列23.-模糊聚类分析原理及实现.docx
  18. ORCA(Optimal Reciprocal Collision Avoidance)笔记
  19. spark常见转换算子(transformation)的操作
  20. Python2.7字符编码详解

热门文章

  1. 阿里开源MNNKit:基于MNN的移动端深度学习SDK,支持安卓和iOS
  2. 一文看懂循环神经网络-RNN(独特价值+优化算法+实际应用)
  3. 百倍提升张量计算:谷歌开源TensorNetwork
  4. 2018年终总结之访问量较大的原创文章
  5. Pytorch固定随机性
  6. chinese_L-12_H-768_A-12的一个坑
  7. 华为徐文伟:用数学和系统工程方法推进未来网络研究
  8. Hinton的胶囊网络不太行?CVPR Oral论文:不比卷积网络更「强」
  9. 突发!美国最大输油管道遭网络攻击关闭!美媒:为其基础设施的脆弱堪忧
  10. 物联网激荡MEMS传感器浪潮