PipedInputStream类与PipedOutputStream类用于在应用程序中创建管道通信.一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进行连接而产生一个通信管道.PipedOutputStream可以向管道中写入数据,PipedIntputStream可以读取PipedOutputStream向管道中写入的数据.这两个类主要用来完成线程之间的通信.一个线程的PipedInputStream对象能够从另外一个线程的PipedOutputStream对象中读取数据.

ps:使用这组I/O流必须在多线程环境下.

首先简单的介绍一下这两个类的实现原理,PipedInputStream和PipedOutputStream的实现原理类似于"生产者-消费者"原理,PipedOutputStream是生产者,PipedInputStream是消费者,在PipedInputStream中有一个buffer字节数组,默认大小为1024,作为缓冲区,存放"生产者"生产出来的东东.还有两个变量,in,out,in是用来记录"生产者"生产了多少,out是用来记录"消费者"消费了多少,in为-1表示消费完了,in==out表示生产满了.当消费者没东西可消费的时候,也就是当in为-1的时候,消费者会一直等待,直到有东西可消费.

因为生产和消费的方法都是synchronized的,所以肯定是生产者先生产出一定数量的东西,消费者才可以开始消费,所以在生产的时候发现in==out,那一定是满了,同理,在消费的时候发现in==out,那一定是消费完了,因为生产的东西永远要比消费来得早,消费者最多可以消费和生产的数量相等的东西,而不会超出.

好了,介绍完之后,看看SUN高手是怎么实现这些功能的.由于buffer(存放产品的通道)这个关键变量在PipedInputStream消费者这个类中,所以要想对buffer操作,只能通过PipedInputStream来操作,因此将产品放入通道的操作是在PipedInputStream中.

存放产品的行为:

  1. protected synchronized void receive(int b) throws IOException {// 这里好像有些问题,因为这个方法是在PipedOutputStream类中调用的,而这个方法是protected的,下面另一个receive方法就不是protected,可能是我的源码有些问题,也请大家帮我看看
  2. checkStateForReceive();// 检测通道是否连接,准备好接收产品
  3. writeSide = Thread.currentThread();// 当前线程是生产者
  4. if (in == out)
  5. awaitSpace();// 发现通道满了,没地方放东西啦,等吧~~
  6. if (in < 0) {// in<0,表示通道是空的,将生产和消费的位置都置成第一个位置
  7. in = 0;
  8. out = 0;
  9. }
  10. buffer[in++] = (byte) (b & 0xFF);
  11. if (in >= buffer.length) {// 如果生产位置到达了通道的末尾,为了循环利用通道,将in置成0
  12. in = 0;
  13. }
  14. }
  15. synchronized void receive(byte b[], int off, int len) throws IOException {// 看,这个方法不是protected的!
  16. checkStateForReceive();
  17. writeSide = Thread.currentThread();
  18. int bytesToTransfer = len;// 需要接收多少产品的数量
  19. while (bytesToTransfer > 0) {
  20. if (in == out)
  21. awaitSpace();
  22. int nextTransferAmount = 0;// 本次实际可以接收的数量
  23. if (out < in) {
  24. nextTransferAmount = buffer.length - in;// 如果消费的当前位置<生产的当前位置,则还可以再生产buffer.length-in这么多
  25. } else if (in < out) {
  26. if (in == -1) {
  27. in = out = 0;// 如果已经消费完,则将in,out置成0,从头开始接收
  28. nextTransferAmount = buffer.length - in;
  29. } else {
  30. nextTransferAmount = out - in;// 如果消费的当前位置>生产的当前位置,而且还没消费完,那么至少还可以再生产out-in这么多,注意,这种情况是因为通道被重复利用而产生的!
  31. }
  32. }
  33. if (nextTransferAmount > bytesToTransfer)// 如果本次实际可以接收的数量要大于当前传过来的数量,
  34. nextTransferAmount = bytesToTransfer;// 那么本次实际只能接收当前传过来的这么多了
  35. assert (nextTransferAmount > 0);
  36. System.arraycopy(b, off, buffer, in, nextTransferAmount);// 把本次实际接收的数量放进通道
  37. bytesToTransfer -= nextTransferAmount;// 算出还剩多少需要放进通道
  38. off += nextTransferAmount;
  39. in += nextTransferAmount;
  40. if (in >= buffer.length) {// 到末尾了,该从头开始了
  41. in = 0;
  42. }
  43. }
  44. }

消费产品的行为:

    1. public synchronized int read() throws IOException {// 消费单个产品
    2. if (!connected) {
    3. throw new IOException("Pipe not connected");
    4. } else if (closedByReader) {
    5. throw new IOException("Pipe closed");
    6. } else if (writeSide != null && !writeSide.isAlive() && !closedByWriter
    7. && (in < 0)) {
    8. throw new IOException("Write end dead");
    9. }
    10. readSide = Thread.currentThread();
    11. int trials = 2;
    12. while (in < 0) {// in<0,表示通道是空的,等待生产者生产
    13. if (closedByWriter) {
    14. /**//* closed by writer, return EOF */
    15. return -1;// 返回-1表示生产者已经不再生产产品了,closedByWriter为true表示是由生产者将通道关闭的
    16. }
    17. if ((writeSide != null) && (!writeSide.isAlive()) && (--trials < 0)) {
    18. throw new IOException("Pipe broken");
    19. }
    20. /**//* might be a writer waiting */
    21. notifyAll();
    22. try {
    23. wait(1000);
    24. } catch (InterruptedException ex) {
    25. throw new java.io.InterruptedIOException();
    26. }
    27. }
    28. int ret = buffer[out++] & 0xFF;
    29. if (out >= buffer.length) {
    30. out = 0;// 如果消费到通道的末尾了,从通道头开始继续循环消费
    31. }
    32. if (in == out) {
    33. /**//* now empty */
    34. in = -1;// 消费的位置和生产的位置重合了,表示消费完了,需要生产者生产,in置为-1
    35. }
    36. return ret;
    37. }
    38. public synchronized int read(byte b[], int off, int len) throws IOException {
    39. if (b == null) {
    40. throw new NullPointerException();
    41. } else if ((off < 0) || (off > b.length) || (len < 0)
    42. || ((off + len) > b.length) || ((off + len) < 0)) {
    43. throw new IndexOutOfBoundsException();
    44. } else if (len == 0) {
    45. return 0;
    46. }
    47. /**//* possibly wait on the first character */
    48. int c = read();// 利用消费单个产品来检测通道是否连接,并且通道中是否有东西可消费
    49. if (c < 0) {
    50. return -1;// 返回-1表示生产者生产完了,消费者也消费完了,消费者可以关闭通道了
    51. }
    52. b[off] = (byte) c;
    53. int rlen = 1;
    54. // 这里没有采用receive(byte [], int ,
    55. // int)方法中System.arrayCopy()的方法,其实用System.arrayCopy()的方法也可以实现
    56. /**//*
    57. * 这是用System.arrayCopy()实现的方法 int bytesToConsume = len - 1; while
    58. * (bytesToConsume > 0 && in >= 0) { int nextConsumeAmount = 0; if (out <
    59. * in) { nextConsumeAmount = in - out; // System.arraycopy(buffer, out,
    60. * b, off, nextConsumeAmount); } else if (in < out) { nextConsumeAmount =
    61. * buffer.length - out; }
    62. *
    63. * if (nextConsumeAmount > bytesToConsume) nextConsumeAmount =
    64. * bytesToConsume; assert (nextConsumeAmount > 0);
    65. * System.arraycopy(buffer, out, b, off, nextConsumeAmount);
    66. * bytesToConsume -= nextConsumeAmount; off += nextConsumeAmount; out +=
    67. * nextConsumeAmount; rlen += nextConsumeAmount; if (out >=
    68. * buffer.length) { out = 0; } if(in == out) { in = -1; } }
    69. */
    70. while ((in >= 0) && (--len > 0)) {
    71. b[off + rlen] = buffer[out++];
    72. rlen++;
    73. if (out >= buffer.length) {
    74. out = 0;
    75. }
    76. if (in == out) {
    77. /**//* now empty */
    78. in = -1;// in==out,表示满了,将in置成-1
    79. }
    80. }
    81. return rlen;
    82. }

PipedInputStream/PipedOutputStream原理的更多相关文章

  1. java 多线程:线程通信-等待通知机制wait和notify方法;(同步代码块synchronized和while循环相互嵌套的差异);管道通信:PipedInputStream;PipedOutputStream;PipedWriter; PipedReader

    1.等待通知机制: 等待通知机制的原理和厨师与服务员的关系很相似: 1,厨师做完一道菜的时间不确定,所以厨师将菜品放到"菜品传递台"上的时间不确定 2,服务员什么时候可以取到菜,必 ...

  2. 系统学习 Java IO (六)----管道流 PipedInputStream/PipedOutputStream

    目录:系统学习 Java IO---- 目录,概览 PipedInputStream 类使得可以作为字节流读取管道的内容. 管道是同一 JVM 内的线程之间的通信通道. 使用两个已连接的管道流时,要为 ...

  3. PipedInputStream和PipedOutputStream详解

    PipedInputStream类与PipedOutputStream类用于在应用程序中创建管道通信.一个PipedInputStream实例对象必须和一个PipedOutputStream实例对象进 ...

  4. java下管道流 PipedOutputStream 与PipedInputStream

    package cn.stat.p2.demo; import java.io.IOException; import java.io.PipedInputStream; import java.io ...

  5. Java I/O流-PipedInputStream、PipedOutputStream

    一.整体代码图 PipedStreamDemo.java import java.io.*; class PipedStreamDemo { public static void main(Strin ...

  6. Java-IO之管道(PipedInputStream和PipedOutputStream)

    java中PipedInputStream和PipedOutputStream分别是管道输入流和管道输出流,它的作用是让多线程可以通过管道进行线程间的通讯,在使用管道通信时,必须将PipedInput ...

  7. java io系列04之 管道(PipedOutputStream和PipedInputStream)的简介,源码分析和示例

    本章,我们对java 管道进行学习. 转载请注明出处:http://www.cnblogs.com/skywang12345/p/io_04.html java 管道介绍 在java中,PipedOu ...

  8. Java IO源码分析(三)——PipedOutputStream和PipedInputStream

    简介 PipedOutputStream和PipedInputStream主要用于线程之间的通信 .二者必须配合使用,也就是一段写入,另一端接收.本质上也是一个中间缓存区,讲数据缓存在PipedInp ...

  9. [Java] I/O底层原理之一:字符流、字节流及其源码分析

    关于 I/O 的类可以分为四种: 关于字节的操作:InputStream 和 OutPutStream: 关于字符的操作:Writer 和 Reader: 关于磁盘的操作:File: 关于网络的操作: ...

随机推荐

  1. IOS开发之---触摸和手势

    Touch:在与设备的多点触摸屏交互时生成. 响应者对象 响应者对象就是可以响应事件并对事件作出处理.在iOS中,存在UIResponder类,它定义了响应者对象的所有方法.UIApplication ...

  2. CF(441D Valera and Swaps)置换群

    题意:1-n的一个排列, p2, ..., pn,f(p)的定义是此排列要交换最少的数对能够回到原排列1,2,3,4...n.给一个排列p.要将其变换成f值为m的排列,问至少要交换几个数对,并输出字典 ...

  3. 2014年百度之星资格赛第二题Disk Schedule

    Problem Description 有非常多从磁盘读取数据的需求,包含顺序读取.随机读取.为了提高效率,须要人为安排磁盘读取. 然而,在现实中,这样的做法非常复杂. 我们考虑一个相对简单的场景. ...

  4. 使用Unicorn-engine 续1

    续上次,在ubuntu server 14.04交叉编译好后,下一步就是在windows上使用了. 在windows上,我主要是用python进行分析程序,因此我最初安装的是官网上的 unicorn- ...

  5. UBUNTU系统常用基本命令

    1.系统基本信息查询查看内核#uname -a 查看Ubuntu版本#cat /etc/issue 查看内核加载的模块#lsmod 查看PCI设备#lspci 查看USB设备#lsusb 查看网卡状态 ...

  6. Ubuntu 12.04 搭建 Eclipse Android 开发环境(转)

    Ubuntu 12.04 搭建 Eclipse Android 开发环境 http://blog.sina.com.cn/s/blog_93dc666c0101b39p.html (2012-09-0 ...

  7. 百度Echarts使用心得

    echarts官网:http://echarts.baidu.com/index.html 最近用了echart,有一下问题需要注意: 1.echarts的使用实例 代码:从地图中取得whitejso ...

  8. Android中进程生命周期的优先级

    “我们不是生产者,我只是大自然的搬运工.” 学习Android最好的途径当然是强大的官方文档了,其中在Processes and Threads一节中对于进程生命周期淘汰优先级,有着详细的介绍.原文如 ...

  9. Mac系统杂项 (持续更新)

    一.调整LaunchPad的图标显示列数和行数 .调整每一列显示图标数量.在我的电脑上(1366 * 768),每列7个个人觉得比较不错 defaults write com.apple.dock s ...

  10. SQL使用记录

    Q:怎么删掉sql server登录时的用户名?(仅仅是删掉那个登录时的提示) A:先关闭数据库登录引擎,然后删除:%AppData%\Microsoft\Microsoft SQL Server\1 ...