Java的AIO基础

Java的AIO基础

Java的IO:

I/O,即 Input/Output(输入/输出) 的简称。就 I/O 而言,概念上有 5 种模型:blocking I/O,nonblocking I/O,I/O multiplexing (select and poll),signal driven I/O (SIGIO),asynchronous I/O (the POSIX aio_functions)。不同的操作系统对上述模型支持不同,UNIX 支持 IO 多路复用。不同系统叫法不同,freebsd 里面叫 kqueue,Linux 叫 epoll。而 Windows2000 的时候就诞生了 IOCP 用以支持 asynchronous I/O。

同步并阻塞 (I/O 方法):服务器实现模式为一个连接启动一个线程,每个线程亲自处理 I/O 并且一直等待 I/O 直到完成,即客户端有连接请求时服务器端就需要启动一个线程进行处理。但是如果这个连接不做任何事情就会造成不必要的线程开销,当然可以通过线程池机制改善这个缺点。I/O 的局限是它是面向流的、阻塞式的、串行的一个过程。对每一个客户端的 Socket 连接 I/O 都需要一个线程来处理,而且在此期间,这个线程一直被占用,直到 Socket 关闭。在这期间,TCP 的连接、数据的读取、数据的返回都是被阻塞的。也就是说这期间大量浪费了 CPU 的时间片和线程占用的内存资源。此外,每建立一个 Socket 连接时,同时创建一个新线程对该 Socket 进行单独通信 (采用阻塞的方式通信)。这种方式具有很快的响应速度,并且控制起来也很简单。在连接数较少的时候非常有效,但是如果对每一个连接都产生一个线程无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况;

同步非阻塞 (NIO 方法):服务器实现模式为一个请求启动一个线程,每个线程亲自处理 I/O,但是另外的线程轮询检查是否 I/O 准备完毕,不必等待 I/O 完成,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有 I/O 请求时才启动一个线程进行处理。NIO 则是面向缓冲区,非阻塞式的,基于选择器的,用一个线程来轮询监控多个数据传输通道,哪个通道准备好了 (即有一组可以处理的数据) 就处理哪个通道。服务器端保存一个 Socket 连接列表,然后对这个列表进行轮询,如果发现某个 Socket 端口上有数据可读时,则调用该 Socket 连接的相应读操作;如果发现某个 Socket 端口上有数据可写时,则调用该 Socket 连接的相应写操作;如果某个端口的 Socket 连接已经中断,则调用相应的析构方法关闭该端口。这样能充分利用服务器资源,效率得到大幅度提高;

异步非阻塞 (AIO 方法,JDK7 发布):服务器实现模式为一个有效请求启动一个线程,客户端的 I/O 请求都是由操作系统先完成了再通知服务器应用去启动线程进行处理,每个线程不必亲自处理 I/O,而是委派操作系统来处理,并且也不需要等待 I/O 完成,如果完成了操作系统会另行通知的。该模式采用了 Linux 的 epoll 模型。

Java的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 的线程池派发的。这里线程池的大小是性能的关键因素。

其中 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。

简单实例:

服务端:

public class MyServer {
	int port;
	
	public MyServer(int port) throws IOException, InterruptedException {
			this.port = port;
			listen();
	}
	
	public void listen() throws IOException, InterruptedException {
		
			ExecutorService executorService = Executors.newCachedThreadPool();
			/*
			 * 创建一个AsynchronousChannelGroup,AsynchronousServerSocketChannel可以绑定一个AsynchronousChannelGroup,
			 * 那么通过这个AsynchronousServerSocketChannel建立的连接都将同属于一个AsynchronousChannelGroup并共享资源
			 */
			AsynchronousChannelGroup asynchronousChannelGroup  = AsynchronousChannelGroup.withCachedThreadPool(executorService, 1);
			final AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(asynchronousChannelGroup);
			
			server.bind(new InetSocketAddress(port));
			
			System.out.println("MyServer.listen()");

			/**
			 * 等待客户端进行连接
			 */
			server.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() {
					ByteBuffer buffer = ByteBuffer.allocate(1024);
				@Override
				public void completed(AsynchronousSocketChannel result, Object attachment) {
					System.out.println("等待连接.......");
					
					try {
						buffer.clear();
						result.read(buffer).get();
						buffer.flip();
						result.write(buffer);
						buffer.flip();
					} catch (InterruptedException | ExecutionException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					} finally {
							try {
								result.close();
								server.accept(null,this);
							} catch (IOException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
							
					}
					
					
					System.out.println("OK");
				}

				@Override
				public void failed(Throwable exc, Object attachment) {
					System.out.println(exc);
				}
				
			});
			Thread.sleep(Integer.MAX_VALUE);
			 
	}
	
	
	
	
	

	public static void main(String[] args) throws IOException, InterruptedException {
			int port = 3370;
			MyServer myServer = new MyServer(port);
	}

}

客户端:

public class MyClient {
		AsynchronousSocketChannel client = null;
		public MyClient() throws IOException {
			client = AsynchronousSocketChannel.open();
			
		}
		
		public void start() throws InterruptedException {
			client.connect(new InetSocketAddress("127.0.0.1", 3370),null, new CompletionHandler<Void, Void>() {

				@Override
				public void completed(Void result, Void attachment) {
					System.out.println("clientOK");
				}

				@Override
				public void failed(Throwable exc, Void attachment) {
				}
			});
			
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			client.read(buffer, null,new CompletionHandler<Integer, Object>() {

				@Override
				public void completed(Integer result, Object attachment) {
					System.out.println(result);
					System.out.println("MyClient.start().new CompletionHandler() {...}.completed()");
				}

				@Override
				public void failed(Throwable exc, Object attachment) {
				}
				
			});
			
			Thread.sleep(Integer.MAX_VALUE);
		}
		
		
		
	public static void main(String[] args) throws IOException, InterruptedException {
			MyClient myClient = new MyClient();
			myClient.start();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值