分享

Java nio入门教程详解(二十八)

 360lec 2016-09-30

3.6 管道

java.nio.channels包中含有一个名为Pipe(管道)的类。广义上讲,管道就是一个用来在两个实体之间单向传输数据的导管。管道的概念对于 Unix(和类 Unix)操作系统的用户来说早就很熟悉了。Unix 系统中,管道被用来连接一个进程的输出和另一个进程的输入。Pipe类实现一个管道范例,不过它所创建的管道是进程内(在Java虚拟机进程内部)而非进程间使用的。参见图 3-10。

图 3-10 Pipe 类层次结构图 3-10 Pipe 类层次结构

Pipe类创建一对提供环回机制的Channel对象。这两个通道的远端是连接起来的,以便任何写在SinkChannel对象上的数据都能出现在SourceChannel对象上。图 3-11 显示了Pipe的类层级。

  1. package java.nio.channels;
  2. public abstract class Pipe {
  3.     public static Pipe open() throws IOException
  4.     public abstract SourceChannel source();
  5.     public abstract SinkChannel sink(); public static abstract class SourceChannel extends AbstractSelectableChannel implements ReadableByteChannel, ScatteringByteChannel
  6.     public static abstract class SinkChannel extends AbstractSelectableChannel implements WritableByteChannel, GatheringByteChannel
  7. }

图 3-11 管道是一对循环的通道图 3-11 管道是一对循环的通道

Pipe实例是通过调用不带参数的Pipe.open()工厂方法来创建的。Pipe类定义了两个嵌套的通道类来实现管路。这两个类是 Pipe.SourceChannel(管道负责读的一端)和 Pipe.SinkChannel(管道负责写的一端)。这两个通道实例是在Pipe对象创建的同时被创建的,可以通过在 Pipe 对象上分别调用source()sink()方法来取回。

此时,您可能在想管道到底有什么作用。您不能使用Pipe在操作系统级的进程间建立一个类Unix 管道(您可以使用SocketChannel来建立)。Pipe的source通道和sink通道提供类似java.io.PipedInputStreamjava.io.PipedOutputStream所提供的功能,不过它们可以执行全部的通道语义。请注意,SinkChannelSourceChannel都由AbstractSelectableChannel引申而来(所以也是从SelectableChannel引申而来),这意味着pipe通道可以同选择器一起使用(参见第四章)。

管道可以被用来仅在同一个Java虚拟机内部传输数据。虽然有更加有效率的方式来在线程之间传输数据,但是使用管道的好处在于封装性。生产者线程和用户线程都能被写道通用的Channel API中。根据给定的通道类型,相同的代码可以被用来写数据到一个文件、socket 或管道。选择器可以被用来检查管道上的数据可用性,如同在socket通道上使用那样地简单。这样就可以允许单个用户线程使用一个Selector来从多个通道有效地收集数据,并可任意结合网络连接或本地工作线程使用。因此,这些对于可伸缩性、冗余度以及可复用性来说无疑都是意义重大的。

Pipes的另一个有用之处是可以用来辅助测试。一个单元测试框架可以将某个待测试的类连接到管道的「写」端并检查管道的「读」端出来的数据。它也可以将被测试的类置于通道的「读」端并将受控的测试数据写进其中。两种场景对于回归测试都是很有帮助的。

管路所能承载的数据量是依赖实现的(implementation-dependent)。唯一可保证的是写到SinkChannel中的字节都能按照同样的顺序在SourceChannel上重现。例 3-11 诠释了如何使用管道。

  1. /*
  2.  *例 3-11 工作线程对一个管道进行写操作
  3.  */
  4. package com.ronsoft.books.nio.channels;
  5. import java.nio.ByteBuffer;
  6. import java.nio.channels.ReadableByteChannel;
  7. import java.nio.channels.WritableByteChannel;
  8. import java.nio.channels.Pipe;
  9. import java.nio.channels.Channels;
  10. import java.util.Random;
  11. /**
  12. * Test Pipe objects using a worker thread.
  13. *
  14. * Created April, 2002
  15. * @author Ron Hitchens (ron@ronsoft.com)
  16. */
  17. public class PipeTest {

  18.     public static void main (String [] argv) throws Exception {
  19.         // Wrap a channel around stdout
  20.         WritableByteChannel out = Channels.newChannel(System.out);
  21.         // Start worker and get read end of channel
  22.         ReadableByteChannel workerChannel = startWorker(10);
  23.         ByteBuffer buffer = ByteBuffer.allocate(100);
  24.         while (workerChannel.read(buffer) >= 0) {
  25.             buffer.flip();
  26.             out.write(buffer);
  27.             buffer.clear();
  28.         }
  29.     }
  30.    
  31.     // This method could return a SocketChannel or
  32.     // FileChannel instance just as easily
  33.     private static ReadableByteChannel startWorker (int reps) throws Exception {
  34.         Pipe pipe = Pipe.open();
  35.         Worker worker = new Worker(pipe.sink(), reps);
  36.         worker.start();
  37.         return (pipe.source());
  38.     }
  39.    
  40.     // -----------------------------------------------------------------
  41.     /**
  42.     * A worker thread object which writes data down a channel.
  43.     * Note: this object knows nothing about Pipe, uses only a
  44.     * generic WritableByteChannel.
  45.     */
  46.     private static class Worker extends Thread {
  47.         WritableByteChannel channel;
  48.         private int reps;

  49.         Worker(WritableByteChannel channel, int reps) {
  50.             this.channel = channel;
  51.             this.reps = reps;
  52.         }

  53.         // Thread execution begins here
  54.         public void run() {
  55.             ByteBuffer buffer = ByteBuffer.allocate(100);
  56.             try {
  57.                 for (int i = 0; i < this.reps; i++) {
  58.                     doSomeWork (buffer);
  59.                     // channel may not take it all at once
  60.                     while (channel.write(buffer) > 0) {
  61.                         // empty
  62.                     }
  63.                 }
  64.                 this.channel.close();
  65.             } catch (Exception e) {
  66.                 // easy way out; this is demo code
  67.                 e.printStackTrace();
  68.             }
  69.         }
  70.        
  71.         private String [] products = {"No good deed goes unpunished", "To be, or what?", "No matter where you go, there you are", "Just say \"Yo\"", "My karma ran over my dogma"};
  72.         private Random rand = new Random();
  73.        
  74.         private void doSomeWork (ByteBuffer buffer) {
  75.             int product = rand.nextInt(products.length);
  76.             buffer.clear();
  77.             buffer.put(products[product].getBytes());
  78.             buffer.put("\r\n".getBytes());
  79.             buffer.flip();
  80.         }
  81.     }
  82. }

Java nio入门教程详解(二十九)

0 0
我们认为:用户的主要目的,是为了获取有用的信息,而不是来点击广告的。因此本站将竭力做好内容,并将广告和内容进行分离,确保所有广告不会影响到用户的正常阅读体验。用户仅凭个人意愿和兴趣爱好点击广告。
我们坚信:只有给用户带来价值,用户才会给我们以回报。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多