java多线程通信(管道通信)

转载自:http://my.oschina.net/u/248570/blog/53226

 进程间通信的方法主要有以下几种:

  (1)管道(Pipe):管道可用于具有亲缘关系进程间的通信,允许一个进程和另一个与它有共同祖先的进程之间进行通信。
  (2)命名管道(named pipe):命名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关 系 进程间的通信。命名管道在文件系统中有对应的文件名。命名管道通过命令mkfifo或系统调用mkfifo来创建。
  (3)信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送 信号给进程本身;linux除了支持Unix早期信号语义函数sigal外,还支持语义符合Posix.1标准的信号函数sigaction(实际上,该函数是基于BSD的,BSD为了实现可靠信号机制,又能够统一对外接口,用sigaction函数重新实现了signal函数)。
  (4)消息(Message)队列:消息队列是消息的链接表,包括Posix消息队列system V消息队列。有足够权限的进程可以向队列中添加消息,被赋予读权限的进程则可以读走队列中的消息。消息队列克服了信号承载信息量少,管道只能承载无格式字节流以及缓冲区大小受限等缺
  (5)共享内存:使得多个进程可以访问同一块内存空间,是最快的可用IPC形式。是针对其他通信机制运行效率较低而设计的。往往与其它通信机制,如信号量结合使用,来达到进程间的同步及互斥。
  (6)内存映射(mapped memory):内存映射允许任何多个进程间通信,每一个使用该机制的进程通过把一个共享的文件映射到自己的进程地址空间来实现它。
  (7)信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
  (8)套接口(Socket):更为一般的进程间通信机制,可用于不同机器之间的进程间通信。起初是由Unix系统的BSD分支开发出来的,但现在一般可以移植到其它类Unix系统上:Linux和System V的变种都支持套接字

而在java中我们实现多线程间通信则主要采用"共享变量"和"管道流"这两种方法

方法一 通过访问共享变量的方式(注:需要处理同步问题) 
方法二 通过管道流
 

其中方法一有两种实现方法,即 
方法一a)通过内部类实现线程的共享变量 
代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class Innersharethread {    
     public static void main(String[] args) {    
         Mythread mythread = new Mythread();    
         mythread.getThread().start();    
         mythread.getThread().start();    
         mythread.getThread().start();    
         mythread.getThread().start();    
     }    
}    
class Mythread {    
     int index = 0 ;    
     
     private class InnerThread extends Thread {    
         public synchronized void run() {    
             while ( true ) {    
                 System.out.println(Thread.currentThread().getName()    
                         + "is running and index is " + index++);    
             }    
         }    
     }    
     
     public Thread getThread() {    
         return new InnerThread();    
     }    
}   
   
/**
  * 通过内部类实现线程的共享变量
  *
  */ 
public class Innersharethread { 
     public static void main(String[] args) { 
         Mythread mythread = new Mythread(); 
         mythread.getThread().start(); 
         mythread.getThread().start(); 
         mythread.getThread().start(); 
         mythread.getThread().start(); 
    
class Mythread { 
     int index = 0
   
     private class InnerThread extends Thread { 
         public synchronized void run() { 
             while ( true ) { 
                 System.out.println(Thread.currentThread().getName() 
                         + "is running and index is " + index++); 
            
        
    
   
     public Thread getThread() { 
         return new InnerThread(); 
    
}

b)通过实现Runnable接口实现线程的共享变量 
代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class Interfacaesharethread {
     public static void main(String[] args) {
         Mythread mythread = new Mythread();
         new Thread(mythread).start();
         new Thread(mythread).start();
         new Thread(mythread).start();
         new Thread(mythread).start();
     }
}
 
/* 实现Runnable接口 */
class Mythread implements Runnable {
     int index = 0 ;
 
     public synchronized void run() {
         while ( true )
             System.out.println(Thread.currentThread().getName() + "is running and
                         the index is " + index++);
     }
}
 
/**
  * 通过实现Runnable接口实现线程的共享变量
  
  */
public class Interfacaesharethread {
     public static void main(String[] args) {
         Mythread mythread = new Mythread();
         new Thread(mythread).start();
         new Thread(mythread).start();
         new Thread(mythread).start();
         new Thread(mythread).start();
     }
}
 
/* 实现Runnable接口 */
class Mythread implements Runnable {
     int index = 0 ;
 
     public synchronized void run() {
         while ( true )
             System.out.println(Thread.currentThread().getName() + "is running and
                         the index is " + index++);
     }
}

方法二(通过管道流): 
代码如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class CommunicateWhitPiping {
     public static void main(String[] args) {
         /**
          * 创建管道输出流
          */
         PipedOutputStream pos = new PipedOutputStream();
         /**
          * 创建管道输入流
          */
         PipedInputStream pis = new PipedInputStream();
         try {
             /**
              * 将管道输入流与输出流连接 此过程也可通过重载的构造函数来实现
              */
             pos.connect(pis);
         } catch (IOException e) {
             e.printStackTrace();
         }
         /**
          * 创建生产者线程
          */
         Producer p = new Producer(pos);
         /**
          * 创建消费者线程
          */
         Consumer c = new Consumer(pis);
         /**
          * 启动线程
          */
         p.start();
         c.start();
     }
}
 
/**
  * 生产者线程(与一个管道输入流相关联)
  *
  */
class Producer extends Thread {
     private PipedOutputStream pos;
 
     public Producer(PipedOutputStream pos) {
         this .pos = pos;
     }
 
     public void run() {
         int i = 8 ;
         try {
             pos.write(i);
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
}
 
/**
  * 消费者线程(与一个管道输入流相关联)
  *
  */
class Consumer extends Thread {
     private PipedInputStream pis;
 
     public Consumer(PipedInputStream pis) {
         this .pis = pis;
     }
 
     public void run() {
         try {
             System.out.println(pis.read());
         } catch (IOException e) {
             e.printStackTrace();
         }
     }
}





转载自:http://blog.csdn.net/isfung/article/details/6321512

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

 

下面来看一个两个线程之间互相通信的例子:

 

建一个发送者的类:

Sender.java

[java]  view plain copy
  1. package com.richer.io;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PipedOutputStream;  
  5.   
  6. /** 
  7.  * 该类用于向另外一个线程发送数据,也就是发送者 
  8.  * @author IsFung 
  9.  */  
  10. public class Sender extends Thread {  
  11.     private PipedOutputStream outputStream = new PipedOutputStream(); //首先先创建一个发送对象  
  12.   
  13.     public PipedOutputStream getOutputStream() { //得到输出流  
  14.         return outputStream;  
  15.     }  
  16.   
  17.     public void run() {  
  18.         String strInfo = new String("Hello! Welcome to my space!"); //发送的数据  
  19.         try {  
  20.             outputStream.write(strInfo.getBytes());  
  21.             outputStream.close();  
  22.         } catch (IOException e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.           
  26.     }  
  27.       
  28. }  

再建一个接收者的类:

Receiver.java

[java]  view plain copy
  1. package com.richer.io;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PipedInputStream;  
  5. /** 
  6.  * 接收者 
  7.  * @author IsFung 
  8.  */  
  9. public class Receiver extends Thread {  
  10.     private PipedInputStream inputStream = new PipedInputStream();// 读取对象  
  11.   
  12.     public PipedInputStream getInputStream() {  
  13.         return inputStream;  
  14.     }  
  15.   
  16.     public void run() {  
  17.         byte[] bytes = new byte[1024];  
  18.   
  19.         try {  
  20.             int length = inputStream.read(bytes);// 接收数据  
  21.             System.out.println("接收到的信息如下:/n" + new String(bytes, 0, length));// 打印出收到的信息  
  22.             inputStream.close();  
  23.         } catch (IOException e) {  
  24.             e.printStackTrace();  
  25.         }  
  26.     }  
  27.   
  28. }  

最后我们编写一个控制程序:

PipedStreamTest.java

[java]  view plain copy
  1. package com.richer.io;  
  2.   
  3. import java.io.IOException;  
  4. import java.io.PipedInputStream;  
  5. import java.io.PipedOutputStream;  
  6.   
  7. public class PipedStreamTest {  
  8.   
  9.     /** 
  10.      *控制程序 
  11.      * @param args 
  12.      */  
  13.     public static void main(String[] args) {  
  14.         Sender sender = new Sender();  
  15.         Receiver receiver = new Receiver();  
  16.           
  17.         PipedOutputStream outputStream = sender.getOutputStream();  
  18.         PipedInputStream inputStream = receiver.getInputStream();  
  19.           
  20.         try {  
  21.             //两个管道相连接  
  22.             //inputStream.connect(outputStream); 这2种都可以  
  23.             outputStream.connect(inputStream);  
  24.         } catch (IOException e) {  
  25.             e.printStackTrace();  
  26.         }  
  27.         //启动线程  
  28.         sender.start();  
  29.         receiver.start();  
  30.     }  
  31.   
  32. }  

 

运行该程序的时候应该会在命令行输出以下信息:

 

接收到的信息如下:

Hello! Welcome to my space!

 

另外,JDK还提供了PipedReader和PipedWriter类,用来处理字符文本的管道通信。它们和PipedInputStream类和PipedOutputStream类使用方法很类似,这里Richer就不多介绍了。

 

使用管道流类可以实现各个程序模块之间的松耦合通信,使用管道流类进行通信的模块,具有强内聚弱耦合的特点,一块模块被替换不会影响到其他的模块。这样就可以在程序中灵活的将多个这样的模块的输入流和输出流相连,以拼装成满足各种应用的程序,而不用对模块内部进行修改。上面例子程序中的Sender和Receiver的输入和输出管道相连,Sender发送的数据就被Receiver接收到了。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值