欢迎您的访问
专注架构,Java,数据结构算法,Python技术分享

八、网络编程之多线程之管道流

引言

java语言中提供了很多输入与输出流,使我们方便了对数据进行操作,其中管道流是一种特殊的流,用于在不同线程间直接传输数据。一个线程发送到输出管道,另一个线程从输入管道中读取数据。通过使用管道,实现不同线程间的通讯,而无须借助临时文件之类的东西了。
在jdk中提供了4个类来使用线程间可以进行通讯:
一堆字节流管道流和一堆字符管道流

PipedInputStream
PipedOutputStream
PipedReader
PipedWriter

字节管道流

一般大家都是知道的只要是流基本上都是成对成对出现的,一边写入一遍读取。现在首先讲解一下 PipedInputStream 和 PipedOutputStream 这对管道流使用步骤。
建立管道输入端和输出端的连接,必须首先创建一个 PipedOutputStream 对象,然后创建一个 PipedInputStream 对象。如下:

PipedOutputStream out = null; 
PipedInputStream in = null; 

对象建立好以后使用 connect() 方法将二者建立连接

out.connect(in); 

该方法在 PipedOutputStream 、PipedInputStream 当中都有,随便调用那个来建立连接都可以,但注意只能建立一次连接,重复建立会抛异常。
不使用 connect() 方法也是可以建立连接的,方法如下:

out = new PipedOutputStream(in ); 

一旦建立了管道,就可以像操作文件一样对管道进行数据读写。
下面线程配合管道流的使用代码编写。

/**
* 写入线程
*/
public class PipedThreadOut implements Runnable {
   /**
    * 管道输出流
    */
   private PipedOutputStream out;
   /**
    * 构造函数
    * @param out
    */
   public PipedThreadOut(PipedOutputStream out) {
       this.out = out;
   }
   /**
    * 写入数据
    */
   private void write() {
       String data = "我是pipedOutputStream流,写入数据了!!!";
       try {
           this.out.write(data.getBytes());
           System.out.println("写入数据为:"+data);

       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           try {
               this.out.close();//关闭输出流
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
   @Override
   public void run() {
       //开始写入
       this.write();
   }
}

/**
* 读取线程
*/
class PipedThreadIn implements Runnable {
   /**
    * 管道输出流
    */
   private PipedInputStream in;
   /**
    * 构造函数
    * @param in
    */
   public PipedThreadIn(PipedInputStream in) {
       this.in = in;
   }
   /**
    * 读取数据
    */
   private void read() {
       //定义一个缓冲区
       byte[] b = new byte[1024];
       //记录读取字节数
       int len;
       String data = "";
       try {
           //开始读取
           while ((len = this.in.read(b)) > 0) {
               data += new String(b,0,len);
           }
           System.out.println("读取数据为:" + data);
       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           try {
               this.in.close();//关闭读取流
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       System.out.println("=====================================");
   }
   @Override
   public void run() {
       //开始读取
       this.read();
   }
}

//调用代码
public class PipedThreadTest {
   public static void main(String[] args) throws IOException, InterruptedException {
       //创建写入流
       PipedOutputStream out = new PipedOutputStream();
       //创建读取流
       PipedInputStream in = new PipedInputStream();
       //为写入和读取建立连接
       out.connect(in);
       //创建写入流线程
       Thread outThread = new Thread(new PipedThreadOut(out));
       //创建读取流线程
       Thread inThread = new Thread(new PipedThreadIn(in));
       //启动线程
       outThread.start();
       Thread.sleep(1000);
       inThread.start();
   }
}

结果:
写入数据为:我是pipedOutputStream流,写入数据了!!!
读取数据为:我是pipedOutputStream流,写入数据了!!!
=====================================

解释一下代码编写的过程
1.首先创建一个输出管道的 runnable 的实现类作为写入数据线程类使用,写入数据需要传入一个输出管道流对象。
2. 在创建一个输入管道的 runnable 的实现类作为读取数据的线程类使用,读取数据需要传入一个输入管道流对象。
3. 在测试类创建一个输出流对象和一个输入流对象。
4. 在创建2个线程将输出和输入对象传到各自对应的 runnable 的实现类中
5. 最后启动2个线程。
注意:一定要将输入和输出流简历连接 connect

字符管道流

字符管道流和字节管道流几乎是一模一样的使用,只需要将输入字节流修改成字符流,以及将输出字节流修改为输出字符流,并且需要将读取缓冲区的 byte 数组修改为 char 数组即可。直接看代码吧!!!

/**
* 写入线程
*/
public class PipedThreadOut implements Runnable {
   /**
    * 管道输出流
    */
   private PipedWriter out;
   /**
    * 构造函数
    * @param out
    */
   public PipedThreadOut(PipedWriter out) {
       this.out = out;
   }
   /**
    * 写入数据
    */
   private void write() {
       String data = "我是pipedWrite流,写入数据了!!!";
       try {
           this.out.write(data);
           System.out.println("写入数据为:"+data);

       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           try {
               this.out.close();//关闭输出流
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
   }
   @Override
   public void run() {
       //开始写入
       this.write();
   }
}

/**
* 读取线程
*/
class PipedThreadIn implements Runnable {
   /**
    * 管道输出流
    */
   private PipedReader in;
   /**
    * 构造函数
    * @param in
    */
   public PipedThreadIn(PipedReader in) {
       this.in = in;
   }
   /**
    * 读取数据
    */
   private void read() {
       //定义一个缓冲区
       char[] b = new char[1024];
       //记录读取字节数
       int len;
       String data = "";
       try {
           //开始读取
           while ((len = this.in.read(b)) > 0) {
               data += new String(b,0,len);
           }
           System.out.println("读取数据为:" + data);
       } catch (IOException e) {
           e.printStackTrace();
       }finally {
           try {
               this.in.close();//关闭读取流
           } catch (IOException e) {
               e.printStackTrace();
           }
       }
       System.out.println("=====================================");
   }
   @Override
   public void run() {
       //开始读取
       this.read();
   }
}

//测试运行代码
public class PipedThreadTest {
   public static void main(String[] args) throws IOException, InterruptedException {
       //创建写入流
       PipedWriter out = new PipedWriter();
       //创建读取流
       PipedReader in = new PipedReader();
       //为写入和读取建立连接
       out.connect(in);
       //创建写入流线程
       Thread outThread = new Thread(new PipedThreadOut(out));
       //创建读取流线程
       Thread inThread = new Thread(new PipedThreadIn(in));
       //启动线程
       outThread.start();
       Thread.sleep(1000);
       inThread.start();
   }
}
//运行结果:
写入数据为:我是pipedWrite流,写入数据了!!!
读取数据为:我是pipedWrite流,写入数据了!!!
=====================================

好了管道流比较简单,和前面学习的流差不多,只是配合线程使用了一下。

 

赞(1) 打赏
版权归原创作者所有,任何形式转载请联系作者;码农code之路 » 八、网络编程之多线程之管道流

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏