java AIO示例
来源:互联网 发布:淘宝女装2016top排行榜 编辑:程序博客网 时间:2024/06/05 04:29
按照《Unix网络编程》的划分,IO模型可以分为:阻塞IO、非阻塞IO、IO复用、信号驱动IO和异步IO,按照POSIX标准来划分只分为两类:同步IO和异步IO。如何区分呢?首先一个IO操作其实分成了两个步骤:发起IO请求和实际的IO操作,同步IO和异步IO的区别就在于第二个步骤是否阻塞,如果实际的IO读写阻塞请求进程,那么就是同步IO,因此阻塞IO、非阻塞IO、IO服用、信号驱动IO都是同步IO,如果不阻塞,而是操作系统帮你做完IO操作再将结果返回给你,那么就是异步IO。阻塞IO和非阻塞IO的区别在于第一步,发起IO请求是否会被阻塞,如果阻塞直到完成那么就是传统的阻塞IO,如果不阻塞,那么就是非阻塞IO。
Java nio 2.0的主要改进就是引入了异步IO(包括文件和网络),这里主要介绍下异步网络IO API的使用以及框架的设计,以TCP服务端为例。首先看下为了支持AIO引入的新的类和接口:
java.nio.channels.AsynchronousChannel
标记一个channel支持异步IO操作。
java.nio.channels.AsynchronousServerSocketChannel
ServerSocket的aio版本,创建TCP服务端,绑定地址,监听端口等。
java.nio.channels.AsynchronousSocketChannel
面向流的异步socket channel,表示一个连接。
java.nio.channels.AsynchronousChannelGroup
异步channel的分组管理,目的是为了资源共享。一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务:处理IO事件和派发CompletionHandler。AsynchronousServerSocketChannel创建的时候可以传入一个 AsynchronousChannelGroup,那么通过AsynchronousServerSocketChannel创建的 AsynchronousSocketChannel将同属于一个组,共享资源。
java.nio.channels.CompletionHandler
需要根据具体应用相应调整,从框架角度出发,需要暴露这样的配置选项给用户。
在介绍完了aio引入的TCP的主要接口和类之后,我们来设想下一个aio框架应该怎么设计。参考非阻塞nio框架的设计,一般都是采用Reactor模式,Reacot负责事件的注册、select、事件的派发;相应地,异步IO有个Proactor模式,Proactor负责 CompletionHandler的派发,查看一个典型的IO写操作的流程来看两者的区别:
Reactor: send(msg) -> 消息队列是否为空,如果为空 -> 向Reactor注册OP_WRITE,然后返回 -> Reactor select -> 触发Writable,通知用户线程去处理 ->先注销Writable(很多人遇到的cpu 100%的问题就在于没有注销),处理Writeable,如果没有完全写入,继续注册OP_WRITE。注意到,写入的工作还是用户线程在处理。
Proactor: send(msg) -> 消息队列是否为空,如果为空,发起read异步调用,并注册CompletionHandler,然后返回。 -> 操作系统负责将你的消息写入,并返回结果(写入的字节数)给Proactor -> Proactor派发CompletionHandler。可见,写入的工作是操作系统在处理,无需用户线程参与。事实上在aio的API 中,AsynchronousChannelGroup就扮演了Proactor的角色。
CompletionHandler有三个方法,分别对应于处理成功、失败、被取消(通过返回的Future)情况下的回调处理:
其中的泛型参数V表示IO调用的结果,而A是发起调用时传入的attchment。
然后初始化一个AsynchronousServerSocketChannel,通过open方法:
通过nio 2.0引入的SocketOption类设置一些TCP选项:
绑定本地地址:
完整示例
Java nio 2.0的主要改进就是引入了异步IO(包括文件和网络),这里主要介绍下异步网络IO API的使用以及框架的设计,以TCP服务端为例。首先看下为了支持AIO引入的新的类和接口:
java.nio.channels.AsynchronousChannel
标记一个channel支持异步IO操作。
java.nio.channels.AsynchronousServerSocketChannel
ServerSocket的aio版本,创建TCP服务端,绑定地址,监听端口等。
java.nio.channels.AsynchronousSocketChannel
面向流的异步socket channel,表示一个连接。
java.nio.channels.AsynchronousChannelGroup
异步channel的分组管理,目的是为了资源共享。一个AsynchronousChannelGroup绑定一个线程池,这个线程池执行两个任务:处理IO事件和派发CompletionHandler。AsynchronousServerSocketChannel创建的时候可以传入一个 AsynchronousChannelGroup,那么通过AsynchronousServerSocketChannel创建的 AsynchronousSocketChannel将同属于一个组,共享资源。
java.nio.channels.CompletionHandler
异步IO操作结果的回调接口,用于定义在IO操作完成后所作的回调工作。AIO的API允许两种方式来处理异步操作的结果:返回的Future模式或者注册CompletionHandler,我更推荐用CompletionHandler的方式,这些handler的调用是由 AsynchronousChannelGroup的线程池派发的。显然,线程池的大小是性能的关键因素。AsynchronousChannelGroup允许绑定不同的线程池,通过三个静态方法来创建:
public static AsynchronousChannelGroup withFixedThreadPool(int nThreads, ThreadFactory threadFactory) throws IOException public static AsynchronousChannelGroup withCachedThreadPool(ExecutorService executor, int initialSize) public static AsynchronousChannelGroup withThreadPool(ExecutorService executor) throws IOException
需要根据具体应用相应调整,从框架角度出发,需要暴露这样的配置选项给用户。
在介绍完了aio引入的TCP的主要接口和类之后,我们来设想下一个aio框架应该怎么设计。参考非阻塞nio框架的设计,一般都是采用Reactor模式,Reacot负责事件的注册、select、事件的派发;相应地,异步IO有个Proactor模式,Proactor负责 CompletionHandler的派发,查看一个典型的IO写操作的流程来看两者的区别:
Reactor: send(msg) -> 消息队列是否为空,如果为空 -> 向Reactor注册OP_WRITE,然后返回 -> Reactor select -> 触发Writable,通知用户线程去处理 ->先注销Writable(很多人遇到的cpu 100%的问题就在于没有注销),处理Writeable,如果没有完全写入,继续注册OP_WRITE。注意到,写入的工作还是用户线程在处理。
Proactor: send(msg) -> 消息队列是否为空,如果为空,发起read异步调用,并注册CompletionHandler,然后返回。 -> 操作系统负责将你的消息写入,并返回结果(写入的字节数)给Proactor -> Proactor派发CompletionHandler。可见,写入的工作是操作系统在处理,无需用户线程参与。事实上在aio的API 中,AsynchronousChannelGroup就扮演了Proactor的角色。
CompletionHandler有三个方法,分别对应于处理成功、失败、被取消(通过返回的Future)情况下的回调处理:
public interface CompletionHandler<V,A> { void completed(V result, A attachment); void failed(Throwable exc, A attachment); void cancelled(A attachment); }
其中的泛型参数V表示IO调用的结果,而A是发起调用时传入的attchment。
第一步,创建一个AsynchronousServerSocketChannel,创建之前先创建一个 AsynchronousChannelGroup,上文提到AsynchronousServerSocketChannel可以绑定一个 AsynchronousChannelGroup,那么通过这个AsynchronousServerSocketChannel建立的连接都将同属于一个AsynchronousChannelGroup并共享资源:
this.asynchronousChannelGroup = AsynchronousChannelGroup .withCachedThreadPool(Executors.newCachedThreadPool(), this.threadPoolSize);
然后初始化一个AsynchronousServerSocketChannel,通过open方法:
this.serverSocketChannel = AsynchronousServerSocketChannel .open(this.asynchronousChannelGroup);
通过nio 2.0引入的SocketOption类设置一些TCP选项:
this.serverSocketChannel .setOption( StandardSocketOption.SO_REUSEADDR,true); this.serverSocketChannel .setOption( StandardSocketOption.SO_RCVBUF,16*1024);
绑定本地地址:
this.serverSocketChannel .bind(new InetSocketAddress("localhost",8080), 100);
完整示例
package com.longshine.nio.aio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousServerSocketChannel;import java.nio.channels.AsynchronousSocketChannel;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;public class Server {AsynchronousServerSocketChannel server;public void init(){try {server = AsynchronousServerSocketChannel.open();server.bind(new InetSocketAddress(8000));System.out.println("服务器启动");Future future = server.accept();AsynchronousSocketChannel client = (AsynchronousSocketChannel)future.get();System.out.println("有客户连接");ByteBuffer buffer = ByteBuffer.allocate(1000);client.read(buffer).get();byte []arr = readBuffer(buffer);System.out.println(new String(arr));} catch (IOException e) {e.printStackTrace();}catch(Exception e){e.printStackTrace();}}public static byte[] readBuffer(ByteBuffer buffer){buffer.flip();int len = buffer.limit() - buffer.position();byte[] ret = new byte[len];System.arraycopy(buffer.array(), 0, ret, 0, len);return ret;}public static void main(String[] args) throws Exception{new Thread(){public void run(){new Server().init();}}.start();Thread.sleep(2000);new Thread(){public void run(){new Client().init();}}.start();}}class Client{public void init(){try {AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();channel.connect(new InetSocketAddress("127.0.0.1",8000)).get();System.out.println("连接服务器成功");ByteBuffer buffer = ByteBuffer.allocate(1000);buffer.put("aaaaaaaaaaaaaa".getBytes());buffer.flip();channel.write(buffer).get();System.out.println("写数据成功");} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}}
CompletedHandler示例
package com.longshine.nio.aio;import java.io.IOException;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousServerSocketChannel;import java.nio.channels.AsynchronousSocketChannel;import java.nio.channels.CompletionHandler;import java.util.concurrent.ExecutionException;public class Server2 {public void init(){try{final AsynchronousServerSocketChannel channel = AsynchronousServerSocketChannel.open();channel.bind(new InetSocketAddress(8000));System.out.println("服务器启动");channel.accept(null, new CompletionHandler<AsynchronousSocketChannel,Object>(){public void completed(AsynchronousSocketChannel result, Object attachment) {try{System.out.println("客户连接");new Thread(new ClientHandler(result)).start();}catch(Exception e){}finally{channel.accept(null, this);}}public void failed(Throwable exc, Object attachment) {System.out.println("失败");}});while(true){System.out.println("我在做自己的事情");Thread.sleep(1000);}}catch(Exception e){}}public static void main(String[] args) throws Exception{new Thread(){public void run(){new Server2().init();}}.start();for(int i = 0; i< 10; i++){new Thread(){public void run(){new Client2().init();}}.start();Thread.sleep(1000);}}public static byte[] readBuffer(ByteBuffer buffer){buffer.flip();int len = buffer.limit() - buffer.position();byte[] ret = new byte[len];System.arraycopy(buffer.array(), 0, ret, 0, len);return ret;}}class Client2{public void init(){try {AsynchronousSocketChannel channel = AsynchronousSocketChannel.open();channel.connect(new InetSocketAddress("127.0.0.1",8000)).get();System.out.println("连接服务器成功");ByteBuffer buffer = ByteBuffer.allocate(1000);channel.read(buffer).get();System.out.println("服务器说:"+new String(Server2.readBuffer(buffer)));} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}catch (IOException e) {e.printStackTrace();}}}
package com.longshine.nio.aio;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousSocketChannel;import java.util.concurrent.ExecutionException;public class ClientHandler implements Runnable{private AsynchronousSocketChannel channel;public ClientHandler(AsynchronousSocketChannel channel){this.channel = channel;}public void run(){ByteBuffer buffer = ByteBuffer.allocate(1000);buffer.put("hello".getBytes());buffer.flip();try {channel.write(buffer).get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}}}
0 0
- java AIO示例
- java AIO示例
- Java AIO总结与示例
- JAVA AIO 服务器与客户端实现示例
- JAVA AIO 服务器与客户端实现示例(代码2)
- java aio
- aio java
- java AIO学习
- Java AIO 入门实例
- Java IO NIO AIO
- java BIO NIO AIO
- [转]Java AIO学习
- Java BIO、NIO、AIO
- java BIO NIO AIO
- java aio 入门
- Java AIO 认识
- Java BIO/NIO/AIO
- java bio nio aio
- Struts2拦截器(二)
- 避免Android内存泄露
- 第十三周 阅读程序 4 运用虚函数的前后对比问题讲解(1)
- Android-PullToRefresh开源项目的使用
- Linux命令-awk
- java AIO示例
- Android应用性能优化
- sql server 独占数据库方法
- 回溯法应用:1,2,5,10四个数任意次数相加得到一个数N
- 新浪微博开发之定义TabBar控件笔记
- 第十二周项目四:点、圆的关系(二)
- spark streaming 错误集锦
- Java基础 二维数组 面向对象(1)
- 第十二周项目四:点,园的关系(三)