Java 7 I/O新功能探秘:同步操作,多播与随机存取

开发 后端
Java 7提供了一个新API访问文件系统,但除此之外,JSR 203(NIO.2)还包含其它很多新特性,这个新版本的确新增了很多改善I/O编程的类。

Java 7将在今年年底正式发布,关于它的介绍也层出不穷,51CTO之前也报导了Java 7的七大新功能,以及Java 7的最新特性、代码示例及性能测试方面的特性。而本文将会着重介绍Java 7 I/O方面的新特性:

关于Java 7的更多内容,欢迎访问51CTO推荐专题:Java 7 下一代Java开发技术详解

◆SeekableByteChannel:随机访问通道;
◆MulticastChannel:允许IP多播的通道;
◆NetworkChannel:新的网络通道超级接口;
◆异步I/O API:新的API使I/O操作可以异步进行。

SeekableByteChannel

首先,Java 7包括新的ByteChannel – SeekableByteChannel,这个通道维护当前的位置,你可以读写该位置,并允许随机访问。使用这个类型的通道,你可以添加多个线程读/写在不同位置相同的线程。

  1. SeekableByteChannel channel1 = Paths.get("Path to file").newByteChannel(); //Simply READ  
  2. SeekableByteChannel channel2 = Paths.get("Path to file").newByteChannel(StandardOpenOption.READ, StandardOpenOption.WRITE); //READ and WRITE 

你可以使用下面这些方法操作位置和通道的大小。

◆long position():返回目前的位置;
◆long size():返回通道连接实体的当前大小,如通道连接的文件大小;
◆position(long newPosition):移动当前位置到某个地方;
◆truncate(long size):根据给定大小截断实体。

position()和truncate()方法简单地返回当前通道,允许链式调用。现在FileChannel实现了新的接口,使用所有FileChannel你都可以实现随机访问,当然你可以用它读取一个文件:

  1. SeekableByteChannel channel = null;  
  2. try {  
  3.     channel = Paths.get("Path to file").newByteChannel(StandardOpenOption.READ);  
  4.     ByteBuffer buf = ByteBuffer.allocate(4096);  
  5.  
  6.     System.out.println("File size: " + channel.size());  
  7.  
  8.     String encoding = System.getProperty("file.encoding");  
  9.  
  10.     while (channel.read(buf) > 0) {  
  11.         buf.rewind();  
  12.  
  13.         byte[] bytearr = new byte[bytebuff.remaining()];  
  14.         buf.get(bytearray);  
  15.         System.out.print(new String(bytearray));  
  16.  
  17.         buf.flip();  
  18.  
  19.         System.out.println("Current position : " + channel.position());  
  20.     }  
  21. } catch (IOException e) {  
  22.     System.out.println("Expection when reading : " + e.getMessage());  
  23.     e.printStackTrace();  
  24. } finally {  
  25.     if (sbc != null){  
  26.         channel.close();  
  27.     }  

#p#
MulticastChannel

这个新的接口允许开启IP多播,因此你可以向一个完整的组发送和接收IP数据报。多播实现了直接绑定本地多播设备,这个接口是通过DatagramChannel和AsynchronousDatagramChannel实现的。下面是从Javadoc中摘取的一个打开DatagramChannel t的简单示例:

  1. NetworkInterface networkInterface = NetworkInterface.getByName("hme0");  
  2. DatagramChannel dc = DatagramChannel.open(StandardProtocolFamily.INET)  
  3.          .setOption(StandardSocketOption.SO_REUSEADDR, true)  
  4.          .bind(new InetSocketAddress(5000))  
  5.          .setOption(StandardSocketOption.IP_MULTICAST_IF, networkInterface);  
  6.  
  7. InetAddress group = InetAddress.getByName("225.4.5.6");  
  8. MembershipKey key = dc.join(group, networkInterface); 

你可以使用以前经常使用的DatagramChannel,但操作方式是多播了,因此你收到的是接口中所有的数据包,你发送的数据包会发到所有组。

NetworkChannel

现在所有网络通道都实现了新的NetworkChannel接口,你可以轻松绑定套接字管道,设置和查询套接字选项,此外,套接字选项也被扩展了,因此你可以使用操作系统特定的选项,对于高性能服务器这非常有用。

异步I/O

现在我们介绍最重要的新特性:异步I/O API,从它的名字我们就知道它有什么功能了,这个新的通道为套接字和文件提供了异步操作。当然,所有操作都是非阻塞的,但对所有异步通道,你也可以执行阻塞操作,所有异步I/O操作都有下列两种形式中的一种:

◆第一个返回java.util.concurrent.Future,代表等待结果,你可以使用Future特性等待I/O操作结束;

◆第二个是使用CompletionHandler创建的,当操作结束时,如回调系统,调用这个处理程序。

下面是它们的一些例子,首先来看看使用Future的例子:

  1. AsynchronousFileChannel channel = AsynchronousFileChannel.open(Paths.get("Path to file"));  
  2. ByteBuffer buffer = ByteBuffer.allocate(capacity);  
  3. Future result = channel.read(buffer, 100); //Read capacity bytes from the file starting at position 100  
  4. boolean done = result.isDone(); //Indicate if the result is already terminated 

你也可以等待结束:

  1. int bytesRead = result.get(); 
  2.  

或等待超时:

  1. int bytesRead = result.get(10, TimeUnit.SECONDS); //Wait at most 10 seconds on the result 
  2.  

再来看看使用CompletionHandler的例子:

  1. Future result = channel.read(buffer, 100, null, new CompletionHandler(){  
  2.     public void completed(Integer result, Object attachement){  
  3.         //Compute the result  
  4.     }  
  5.  
  6.     public void failed(Throwable exception, Object attachement){  
  7.         //Answer to the fail  
  8.     }  
  9. }); 

正如你所看到的,你可以给操作一个附件,在操作末尾给CompletionHandler,当然,你可以把null当作一个附件提供,你可以传递任何你想传递的,如用于AsynchronousSocketChannel的Connection,或用于读操作的ByteBuffer。

  1. Future result = channel.read(buffer, 100, buffer, new CompletionHandler(){  
  2.     public void completed(Integer result, ByteBuffer buffer){  
  3.         //Compute the result  
  4.     }  
  5.  
  6.     public void failed(Throwable exception, ByteBuffer buffer){  
  7.         //Answer to the fail  
  8.     }  
  9. }); 

正如你所看到的,CompletionHandle也提供Future元素表示等待结果,因此你可以合并这两个格式。下面是NIO.2中的所有异步通道:

◆AsynchronousFileChannel:读写文件的异步通道,这个通道没有全局位置,因此每个读写操作都需要一个位置,你可以使用不同的线程同时访问文件的不同部分,当你打开这个通道时,必须指定READ或WRITE选项;

◆AsynchronousSocketChannel:用于套接字的一个简单异步通道,连接、读/写、分散/聚集方法全都是异步的,读/写方法支持超时;

◆AsynchronousServerSocketChannel:用于ServerSocket的异步通道,accept()方法是异步的,当连接被接受时,调用CompletionHandler,这种连接的结果是一个AsynchronousSocketChannel;

◆AsynchronousDatagramChannel:用于数据报套接字的通道,读/写(连接)和接收/发送(无连接)方法是异步的。

#p#

分组

当你使用AsynchronousChannels时,有线程调用完整的处理程序,这些线程被绑定到一个AsynchronousChannelGroup组,这个组包含一个线程池,它封装了所有线程共享的资源,你可以使用线程池来调用这些组,AsynchronousFileChannel可以使用它自己的组创建,将ExecutorService作为一个参数传递给open()方法,在open方法中,通道是使用AsynchronousChannelGroup创建的,如果你不给它一个组,或传递一个NULL,它就会使用默认组。通道被认为是属于组的,因此,如果组关闭了,通道也就关闭了。你可以使用ThreadFactory创建一个组:

  1. ThreadFactory myThreadFactory = Executors.defaultThreadFactory();  
  2. AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withFixedThreadPool(25, threadFactory); 
  3.  

或使用一个ExecutorService:

  1. ExecutorService service = Executors.newFixedThreadPool(25);  
  2. AsynchronousChannelGroup channelGroup = AsynchronousChannelGroup.withThreadPool(service);
  3.  

而且你可以很容易地使用它:

  1. AsynchronousSocketChannel socketChannel = AsynchronousSocketChannel.open(channelGroup); 
  2.  

你可以使用在组上使用shutdown()方法关闭组,关闭之后,你就不能使用这个组创建更多的通道,当所有通道关闭后,组也终止了,处理程序结束,资源也释放了。

当你使用任何类型的池和CompletionHandler时,你必须要注意一点,不要在CompletionHandler内使用阻塞或长时间操作,如果所有线程都被阻塞,整个应用程序都会被阻塞掉。如果你有自定义或缓存的线程池,它会使队列无限制地增长,最终导致OutOfMemoryError。

我想我把新的异步I/O API涵盖的内容讲得差不多了,当然这不是一两句话可以说清楚的,也不是每一个人都会使用到它们,但在某些时候它确实很有用,Java支持这种I/O操作终归是一件好事。如果我的代码中有什么错误我表示道歉,因为我也是刚刚才接触。

原文名:Java 7 : New I/O features (Asynchronous operations, multicasting, random access) with JSR 203 (NIO.2)

原文出处:www.baptiste-wicht.com/2010/04/java-7-new-io-features-asynchronous-operations-multicasting-random-access-with-jsr-203-nio-2/

【编辑推荐】

  1. 再探Java 7:最新特性更新、代码示例及性能测试
  2. Java 7的第一类函数:学习闭包的使用
  3. Java 7已经完成的七大新功能预览
  4. Java 7新功能代码范例
  5. 开发热点周报:Java 7闭包引争议 PDC大会精彩纷呈
责任编辑:王晓东 来源: IT168
相关推荐

2009-12-16 10:41:37

Ruby随机存取文件

2009-05-25 15:17:40

C++随机存取文件

2018-03-28 08:52:53

阻塞非阻塞I

2015-08-10 14:39:46

Java 操作建议

2009-11-26 14:16:06

Java 7

2021-05-20 10:36:30

Chrome浏览器系统技巧

2010-06-29 09:23:09

JDK 7I|ONIO.2

2010-03-17 15:22:14

2009-08-31 18:40:01

Java 7新功能

2011-08-25 09:56:49

数据访问

2012-07-10 10:08:32

红帽RHEL 7

2018-11-05 11:20:54

缓冲IO

2015-07-21 15:56:41

虚拟化存储方式数据中心

2013-05-28 10:08:41

IO输出

2009-09-22 15:15:02

Windows 7新功文件搜索Windows Sea

2009-09-22 15:24:20

Windows 7新功文件管理

2011-04-20 09:20:00

Windows 8

2009-02-18 21:16:16

2020-08-07 08:03:37

IONetty

2009-08-21 18:59:53

远程管理Windows
点赞
收藏

51CTO技术栈公众号