[转]Java AIO学习
java AIO学习
转载 http://blog.csdn.net/zhongweijian/article/details/8005444
系统I/O 可分为阻塞型, 非阻塞同步型以及非阻塞异步型[1, 2]. 阻塞型I/O意味着控制权只到调用操作结束了才会回到调用者手里. 结果调用者被阻塞了, 这段时间了做不了任何其它事情. 更郁闷的是,在等待IO结果的时间里,调用者所在线程此时无法腾出手来去响应其它的请求,这真是太浪费资源了。拿read()操作来说吧, 调用此函数的代码会一直僵在此处直至它所读的socket缓存中有数据到来.
相比之下,非阻塞同步是会立即返回控制权给调用者的。调用者不需要等等,它从调用的函数获取两种结果:要么此次调用成功进行了;要么系统返回错误标识告诉调用者当前资源不可用,你再等等或者再试度看吧。比如read()操作, 如果当前socket无数据可读,则立即返回EWOULBLOCK/EAGAIN,告诉调用read()者"数据还没准备好,你稍后再试".
在非阻塞异步调用中,稍有不同。调用函数在立即返回时,还告诉调用者,这次请求已经开始了。系统会使用另外的资源或者线程来完成这次调用操作,并在完成的时候知会调用者(比如通过回调函数)。拿Windows的ReadFile()或者POSIX的aio_read()来说,调用它之后,函数立即返回,操作系统在后台同时开始读操作。
在以上三种IO形式中,非阻塞异步是性能最高、伸缩性最好的。
这篇文章探讨不同的I/O利用机制并提供一种跨平台的设计模式(解决方案). 希望此文可以给于TCP高性能服务器开发者一些帮助,选择最佳的设计方案。下面我们会比较 Java, c#, C++各自对探讨方案的实现以及性能. 我们在文章的后面就不再提及阻塞式的方案了,因为阻塞式I/O实在是缺少可伸缩性,性能也达不到高性能服务器的要求。
两种IO多路复用方案: Reactor andProactor
一般情况下,I/O 复用机制需要事件分享器(event demultiplexor [1, 3]). 事件分享器的作用,即将那些读写事件源分发给各读写事件的处理者,就像送快递的在楼下喊: 谁的什么东西送了, 快来拿吧。开发人员在开始的时候需要在分享器那里注册感兴趣的事件,并提供相应的处理者(event handlers),或者是回调函数; 事件分享器在适当的时候会将请求的事件分发给这些handler或者回调函数.
涉及到事件分享器的两种模式称为:Reactor and Proactor [1]. Reactor模式是基于同步I/O的,而Proactor模式是和异步I/O相关的. 在Reactor模式中,事件分离者等待某个事件或者可应用或个操作的状态发生(比如文件描述符可读写,或者是socket可读写),事件分离者就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。
而在Proactor模式中,事件处理者(或者代由事件分离者发起)直接发起一个异步读写操作(相当于请求),而实际的工作是由操作系统来完成的。发起时,需要提供的参数包括用于存放读到数据的缓存区,读的数据大小,或者用于存放外发数据的缓存区,以及这个请求完后的回调函数等信息。事件分离者得知了这个请求,它默默等待这个请求的完成,然后转发完成事件给相应的事件处理者或者回调。举例来说,在Windows上事件处理者投递了一个异步IO操作(称有overlapped的技术),事件分离者等IOCompletion事件完成[1]. 这种异步模式的典型实现是基于操作系统底层异步API的,所以我们可称之为“系统级别”的或者“真正意义上”的异步,因为具体的读写是由操作系统代劳的。
举另外个例子来更好地理解Reactor与Proactor两种模式的区别。这里我们只关注read操作,因为write操作也是差不多的。下面是Reactor的做法:
- 某个事件处理者宣称它对某个socket上的读事件很感兴趣;
- 事件分离者等着这个事件的发生;
- 当事件发生了,事件分离器被唤醒,这负责通知先前那个事件处理者;
- 事件处理者收到消息,于是去那个socket上读数据了. 如果需要,它再次宣称对这个socket上的读事件感兴趣,一直重复上面的步骤;
下面再来看看真正意义的异步模式Proactor是如何做的:
- 事件处理者直接投递发一个写操作(当然,操作系统必须支持这个异步操作). 这个时候,事件处理者根本不关心读事件,它只管发这么个请求,它魂牵梦萦的是这个写操作的完成事件。这个处理者很拽,发个命令就不管具体的事情了,只等着别人(系统)帮他搞定的时候给他回个话。
- 事件分离者等着这个读事件的完成(比较下与Reactor的不同);
- 当事件分离者默默等待完成事情到来的同时,操作系统已经在一边开始干活了,它从目标读取数据,放入用户提供的缓存区中,最后通知事件分离者,这个事情我搞完了;
- 事件分享者通知之前的事件处理者: 你吩咐的事情搞定了;
- 事件处理者这时会发现想要读的数据已经乖乖地放在他提供的缓存区中,想怎么处理都行了。如果有需要,事件处理者还像之前一样发起另外一个写操作,和上面的几个步骤一样。
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousChannelGroup; import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; public class EchoAioServer { private final int port; public static void main(String args[]) { int port = 8000; new EchoAioServer(port); } public EchoAioServer(int port) { this.port = port; listen(); } private void listen() { try { ExecutorService executorService = Executors.newCachedThreadPool(); AsynchronousChannelGroup threadGroup = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1); try (AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(threadGroup)) { server.bind(new InetSocketAddress(port)); System.out.println("Echo listen on " + port); server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { final ByteBuffer echoBuffer = ByteBuffer.allocateDirect(1024); public void completed(AsynchronousSocketChannel result, Object attachment) { System.out.println("waiting ...."); try { echoBuffer.clear(); result.read(echoBuffer).get(); echoBuffer.flip(); // echo data result.write(echoBuffer); echoBuffer.flip(); // System.out.println("Echoed '" + new String(echoBuffer.array()) + "' to " + result); } catch (InterruptedException | ExecutionException e) { System.out.println(e.toString()); } finally { try { result.close(); server.accept(null, this); } catch (Exception e) { System.out.println(e.toString()); } } System.out.println("done..."); } @Override public void failed(Throwable exc, Object attachment) { System.out.println("server failed: " + exc); } }); try { // Wait for ever Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException ex) { System.out.println(ex); } } } catch (IOException e) { System.out.println(e); } } }
import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.CompletionHandler; import java.util.concurrent.ExecutionException; public class EchoAioClient { private final AsynchronousSocketChannel client ; public EchoAioClient() throws Exception{ client = AsynchronousSocketChannel.open(); } public void start()throws Exception{ client.connect(new InetSocketAddress("127.0.0.1",8000),null,new CompletionHandler<Void,Void>() { @Override public void completed(Void result, Void attachment) { try { client.write(ByteBuffer.wrap("this is a test".getBytes())).get(); System.out.println("send data to server"); } catch (Exception ex) { ex.printStackTrace(); } } @Override public void failed(Throwable exc, Void attachment) { exc.printStackTrace(); } }); final ByteBuffer bb = ByteBuffer.allocate(1024); client.read(bb, null, new CompletionHandler<Integer,Object>(){ @Override public void completed(Integer result, Object attachment) { System.out.println(result); System.out.println(new String(bb.array())); } @Override public void failed(Throwable exc, Object attachment) { exc.printStackTrace(); } } ); try { // Wait for ever Thread.sleep(Integer.MAX_VALUE); } catch (InterruptedException ex) { System.out.println(ex); } } public static void main(String args[])throws Exception{ new EchoAioClient().start(); } }
Echo listen on 8000 waiting .... done...
client输出:
send data to server 14 this is a test
[转]Java AIO学习相关推荐
- Java BIO、NIO、AIO 学习
2019独角兽企业重金招聘Python工程师标准>>> 先来个例子理解一下概念,以银行取款为例: 同步 : 自己亲自出马持银行卡到银行取钱(使用同步IO时,Java自己处理IO读写) ...
- Java基础学习笔记(二)_Java核心技术(进阶)
本篇文章的学习资源来自Java学习视频教程:Java核心技术(进阶)_华东师范大学_中国大学MOOC(慕课) 本篇文章的学习笔记即是对Java核心技术课程的总结,也是对自己学习的总结 文章目录 Jav ...
- java aio nio bio_3. 彤哥说netty系列之Java BIO NIO AIO进化史
你好,我是彤哥,本篇是netty系列的第三篇. 欢迎来我的公从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们介绍了IO的五种模型,实际上Java只支持其中的三种,即BIO/NIO/ ...
- 【大学四年自学Java的学习路线】写了一个月,这是一份最适合普通大众、非科班的路线,祝你零基础快速找到一份满意的工作
零基础自学 Java,大概多久可以找到工作? 最近又有一个读者"在你的世界各地"向我提了上面这个问题.但说实话,这个问题并不太好问答.因为 Java 是一门"历史悠久&q ...
- 【大学四年自学Java的学习路线】观语如临情中景,无限感激言岂尽。 自知无兄难过河,谢言不叙恩情记!
零基础自学 Java,大概多久可以找到工作? 最近又有一个读者"在你的世界各地"向我提了上面这个问题.但说实话,这个问题并不太好问答.因为 Java 是一门"历史悠久&q ...
- Java NIO 学习笔记(五)----路径、文件和管道 Path/Files/Pipe
目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...
- 史上最全面的Java高级学习体系(没有之一)
https://www.tuicool.com/articles/uqYbUnJ 前几天,有一位同学问我说:"George老师,我现在出来工作4年左右了,可现在我总觉得我在工作中有好多的技术 ...
- Java EE学习心得
–Java EE学习心得 1. 称为编程专家的秘诀是: 思考-----编程--------思考------编程--.. 编程不能一步到位,不能一上来就编,必须先思考如何写,怎样写?然后再编程 ...
- java web学习项目20套源码完整版
java web学习项目20套源码完整版 自己收集的各行各业的都有,这一套源码吃遍所有作业项目! 1.BBS论坛系统(jsp+sql) 2.ERP管理系统(jsp+servlet) 3.OA办公自动化 ...
最新文章
- Mac OS X如何进行字体管理
- Google 排名第一的语言,引数十万人关注:搞定它,技术大牛都甘拜下风
- javascript定义对象写法(个人整理)
- wps office oa控件 痕迹_WPS大更新,Office的付费功能免费用,我不会是最后一个知道的吧?...
- 【数值分析】常微分方程数值解:欧拉公式
- 开放下载 | 《Knative 云原生应用开发指南》开启云原生时代 Serverless 之门
- IOS开发学习记录第2天之熟悉Xcode常用快捷键
- 玩! 框架:为什么我会爱上它
- 中科院计算机学院王宏,王宏-中国科学院大学-UCAS
- GridView样式
- WPS Office 2019 For Linux 设置显示语言
- maya2018 + VS2017 C++编译环境搭建
- JSOI2008 小店购物
- 这个地方沸腾,高手争雄,至尊大决战,从天上杀到地下,又从地上打到云霄上!
- 生产注意事项(分片集群)
- S7-1200添加CALCULATE 指令
- android相机曝光度调节,手机摄影很难?这有份超全的安卓相机操作指南,专业模式一点就透...
- 安装oaj2se出现问题
- 5.5 listen() --- 如果有“人”,请叫我?
- jquery $.fn $.fx是什么意思有什么用
热门文章
- JS实现Unix时间戳(Unix timestamp)转换工具-toolfk程序员工具网
- DLT(Diagnostic Log and Trace)嵌入式系统程序运行记录
- 数据持久化------Archiving(归档,解档)
- virtualbox cannot access the kernel driver的解决办法
- 如何生成项目的chm文档
- vmware workstation 8上面装vsphere5
- Asp.net MVC 示例项目Suteki.Shop分析之---ViewData
- html对字符串判空,使用XslCompiledTransform获取html作为字符串。结果为空
- 移除UTF-8文件头的BOM
- python token 访问控制_python 产生token及token验证