Java网络编程——真正的异步IO(AIO)

                        真正的异步IO(AIO)

       NIO虽然说是一种新的IO,可以用一个线程来处理IO读写的问题,防止IO读写一直阻塞线程,充分利用线程资源。但实际上NIO还是同步IO,比如说读IO时,数据量很大,线程实际上还是会阻塞在读操作上。而AIO就是真正意义上的异步IO了。
       Java在JDK7增加了AIO,分别有三个新的异步通道,AsynchronousFileChannel,AsynchronousSocketChannel和AsynchronousServerSocketChannel,好吧,名字确实都比较长,但看名字就知道这些类有什么作用了。在使用AIO时,我们调用读写数据的接口时,其实相当于开启了一个异步任务,这个异步任务会在后台进行,然后通过Java的Executor框架,可以得到异步的执行结果。比如下面这段代码,就是用AIO异步读到一个文件中的内容
 
package study.io.aio;

import java.io.IOException;
import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

public class AIOFileTest {
	public static void main(String[] args) {
	
		Path path = Paths.get("D:\\Project\\eclipse\\Study\\test.txt");
		try {
			AsynchronousFileChannel afc = AsynchronousFileChannel.open(path);
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			Future future = afc.read(buffer, 0);
			System.out.println("我是异步输入,此时异步读文件");
			int length = future.get();// 得到输入数量,这个操作是阻塞的
			buffer.flip();// 把limit设置成position,position设置成0,方便读取
			String str = Charset.defaultCharset().decode(buffer).toString();
			System.out.println(str);
		} catch (IOException | InterruptedException | ExecutionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
执行结果是:
我是异步输入,此时异步读文件
你好啊
我是小兵
这里的future.get阻塞并不是因为刚开启读操作而阻塞,而是因为要获取执行结果,而读操作还未结束,要等到读操作结束的阻塞,如果在读操作结束后再get其实就不会阻塞了,这也是AIO的方便之处,在需要的地方阻塞,在不需要的地方异步,这样才是真正的充分利用了线程资源并且更方便地实现业务功能。
     上面是使用了AIO的将来式,AIO还有一种实现方式是回调式,也就是在异步操作结束后会进行观察者回调,这种方式在很多时候其实更加方便。还是读文件的例子,下面的代码使用了回调式。

package study.io.aio;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousFileChannel;
import java.nio.channels.CompletionHandler;
import java.nio.charset.Charset;
import java.nio.file.Path;
import java.nio.file.Paths;

public class AIOFileTest {
	public static void main(String[] args) {

		Path path = Paths.get("D:\\Project\\eclipse\\Study\\test.txt");
		try {
			AsynchronousFileChannel afc = AsynchronousFileChannel.open(path);
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			afc.read(buffer, 0, buffer, new CompletionHandler() {

				@Override
				public void completed(Integer arg0, ByteBuffer buffer) {
					buffer.flip();// 把limit设置成position,position设置成0,方便读取
					String str = Charset.defaultCharset().decode(buffer).toString();
					System.out.println(str);
				}

				@Override
				public void failed(Throwable arg0, ByteBuffer arg1) {
					arg0.printStackTrace();
				}

			});
			System.out.println("我是异步输入,此时异步读文件");
			Thread.sleep(3000);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
 这里的输出结果也是:
我是异步输入,此时异步读文件
你好啊
我是小兵
并且在这段代码的最后,我加了Thread.sleep(3000)来让主线程休眠3秒,因为读文件是在异步线程中执行的,如果主线程结束了,
异步线程也会停止工作,就不能读完文件了。首先打印出了"我是异步输入,此时异步读文件“表示确实是异步操作。而且因为使用了异步
我们就不需要知道读文件操作何时结束,并且不需要使用get方法来阻塞当前线程来得到执行结果了,我们只需要在回调中做相应的业务逻辑
处理即可。
另外两个AIO类的使用跟File的AIO使用相似。在Netty框架中,更是把AIO使用得淋漓精致,Netty也成为Java网络框架的杰出代码。弄懂了Java的
BIO、NIO和AIO之后,再学Netty就会比较容易理解了。


你可能感兴趣的:(学习)