java7 AIO / NIO 2 小记

来源:互联网 发布:mac显示桌面快捷键 编辑:程序博客网 时间:2024/06/04 07:11

概述

JDK7 已经大致确定发布时间。JSR 203 提出很久了。2009.11.13,JDK7 M5(b76)已经发布。JSR 203 习惯上称为 NIO.2,主要包括新的:

  • 异步 I/O(简称 AIO);
  • Multicase 多播;
  • Stream Control Transport Protocol(SCTP);
  • 文件系统 API;
  • 以及一些 I/O API 的更新,例如:java.io.File.toPath,NetworkChannel 的完整抽象,等等。
java的io技术发展真是迅速,nio出了不久,接着就出nio2,异步io,Asynchronous IO,也叫 AIO,简单来说Java IO 的发展:

BIO  -> NIO -> AIO,Jva IO 性能逐步突飞猛进,谁还在说IO是Java的硬伤!


BIO几乎已经是老掉牙的东西,最简单,性能很差,不详说了;

NIO让人惊讶的IO性能飞跃,由于java5就开始有了,网上教程也满大街,著名的实用框架有 Netty 和 Mina,不多说了;

AIO,异步IO,这个就不是很为人所很熟知了,java7以后引入的异步IO,引入不少的新操作,小记下:

文件系统 API

File类其实名字有点儿误导人,它并不是指真正的文件,它的本质是用一种依赖系统的路径名来描述文件或者目录。这个通俗点儿讲不就是path

public static void main(String[] args) {        //PS: task 是桌面上的一个文本文件        //获得path方法一,e:/logs/access.log        Path path = FileSystems.getDefault().getPath("/home/conquer/Desktop", "task");        System.out.println(path.getNameCount());        //获得path方法二,用File的toPath()方法获得Path对象        File file = new File("/home/conquer/Desktop/task");        Path pathOther = file.toPath();// File 到 Paht的转换        //0,说明这两个path是相等的        System.out.println(path.compareTo(pathOther));        //获得path方法三        Path path3 = Paths.get("/home/conquer/Desktop", "task");        System.out.println(path3.toString());        //join two paths        Path path4 = Paths.get("/home/conquer/Desktop");        System.out.println("path4: " + path4.resolve("task"));        System.out.println("--------------分割线---------------");        try {            if(Files.isReadable(path)){                //注意此处的newBufferedRead的charset参数,如果和所要读取的文件的编码不一致,则会抛出异常                //java的新特性,不用自己关闭流                BufferedReader br = Files.newBufferedReader(path, Charset.defaultCharset());//new BufferedReader(new FileReader(new File("e:/logs/access.log")));//                String line = "";                while((line = br.readLine()) != null){                    System.out.println(line);                }                br.close();            }else{                System.err.println("cannot readable");            }        } catch (IOException e) {            System.err.println("error charset");        }    }    public static void main0(String[] args) {        /** nio2 */        Path file = Paths.get("/home/conquer/Desktop/task");        System.out.println("file name:" + file.getFileName());        System.out.println("name count:" + file.getNameCount());        System.out.println("parent:" + file.getParent() + " root:"                + file.getRoot());        File file1=file.toFile();        System.out.println(file1.exists());        //其他定义方式        /**Define an Absolute Path*///        Path path = Paths.get("C:/rafaelnadal/tournaments/2009/BNP.txt");//        Path path = Paths.get("C:/rafaelnadal/tournaments/2009", "BNP.txt");//        Path path = Paths.get("C:", "rafaelnadal/tournaments/2009", "BNP.txt");//        Path path = Paths.get("C:", "rafaelnadal", "tournaments", "2009", "BNP.txt");//        /**Define a Path Relative to the File Store Root*///        Path path = Paths.get("/rafaelnadal/tournaments/2009/BNP.txt");//        Path path = Paths.get("/rafaelnadal","tournaments/2009/BNP.txt");//        /**Define a Path Relative to the Working Folder*///        Path path = Paths.get("rafaelnadal/tournaments/2009/BNP.txt");//        Path path = Paths.get("rafaelnadal","tournaments/2009/BNP.txt");    }

异步 I/O(简称 AIO)

  • AIO 的核心概念:发起非阻塞方式的 I/O 操作。当 I/O 操作完成时通知。
  • 应用程序的责任就是:什么时候发起操作? I/O 操作完成时通知谁?

AIO 的 I/O 操作,有两种方式的 API 可以进行:Future 方式  和 Callback 方式。

Future 方式:即提交一个 I/O 操作请求(accept/read/write),返回一个 Future。然后您可以对 Future 进行检查(调用get(timeout)),确定它是否完成,或者阻塞 IO 操作直到操作正常完成或者超时异常。使用 Future 方式很简单,需要注意的是,因为Future.get()是同步的,所以如果不仔细考虑使用场合,使用 Future 方式可能很容易进入完全同步的编程模式,从而使得异步操作成为一个摆设。如果这样,那么原来旧版本的 Socket API 便可以完全胜任,大可不必使用异步 I/O.

Callback 方式

Callback 方式:即提交一个 I/O 操作请求,并且指定一个 CompletionHandler。当异步 I/O 操作完成时,便发送一个通知,此时这个 CompletionHandler 对象的 completed 或者 failed 方法将会被调用。

JAVA AIO 示例代码:

服务端:

package 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.nio.charset.Charset;import java.util.concurrent.ExecutionException;import java.util.concurrent.Future;import java.util.concurrent.TimeUnit;import java.util.concurrent.TimeoutException;public class AIOServer {    public final static int PORT = 9888;    private AsynchronousServerSocketChannel server;    public AIOServer() throws IOException {        server = AsynchronousServerSocketChannel.open().bind(                new InetSocketAddress(PORT));    }    public void startWithFuture() throws InterruptedException,            ExecutionException, TimeoutException {        while (true) {// 循环接收客户端请求            Future<AsynchronousSocketChannel> future = server.accept();            AsynchronousSocketChannel socket = future.get();// get() 是为了确保 accept 到一个连接            handleWithFuture(socket);        }    }    public void handleWithFuture(AsynchronousSocketChannel channel) throws InterruptedException, ExecutionException, TimeoutException {        ByteBuffer readBuf = ByteBuffer.allocate(2);        readBuf.clear();        while (true) {// 一次可能读不完            //get 是为了确保 read 完成,超时时间可以有效避免DOS攻击,如果客户端一直不发送数据,则进行超时处理            Integer integer = channel.read(readBuf).get(10, TimeUnit.SECONDS);            System.out.println("read: " + integer);            if (integer == -1) {                break;            }            readBuf.flip();            System.out.println("received: " + Charset.forName("UTF-8").decode(readBuf));            readBuf.clear();        }    }    public void startWithCompletionHandler() throws InterruptedException,            ExecutionException, TimeoutException {        server.accept(null,                new CompletionHandler<AsynchronousSocketChannel, Object>() {                    public void completed(AsynchronousSocketChannel result, Object attachment) {                        server.accept(null, this);// 再此接收客户端连接                        handleWithCompletionHandler(result);                    }                    @Override                    public void failed(Throwable exc, Object attachment) {                        exc.printStackTrace();                    }                });    }    public void handleWithCompletionHandler(final AsynchronousSocketChannel channel) {        try {            final ByteBuffer buffer = ByteBuffer.allocate(4);            final long timeout = 10L;            channel.read(buffer, timeout, TimeUnit.SECONDS, null, new CompletionHandler<Integer, Object>() {                @Override                public void completed(Integer result, Object attachment) {                    System.out.println("read:" + result);                    if (result == -1) {                        try {                            channel.close();                        } catch (IOException e) {                            e.printStackTrace();                        }                        return;                    }                    buffer.flip();                    System.out.println("received message:" + Charset.forName("UTF-8").decode(buffer));                    buffer.clear();                    channel.read(buffer, timeout, TimeUnit.SECONDS, null, this);                }                @Override                public void failed(Throwable exc, Object attachment) {                    exc.printStackTrace();                }            });        } catch (Exception e) {            e.printStackTrace();        }    }    public static void main(String args[]) throws Exception {//        new AIOServer().startWithFuture();        new AIOServer().startWithCompletionHandler();        Thread.sleep(100000);    }}


客户端:

package aio;import java.net.InetSocketAddress;import java.nio.ByteBuffer;import java.nio.channels.AsynchronousSocketChannel;public class AIOClient {    public static void main(String... args) throws Exception {        AsynchronousSocketChannel client = AsynchronousSocketChannel.open();        client.connect(new InetSocketAddress("localhost", 9888)).get();        client.write(ByteBuffer.wrap("123456789".getBytes()));        Thread.sleep(1111111);    }}

AIO模型,简单,高效,以后的IO通信就用它了!!!

0 0
原创粉丝点击