7.3 线程间通信
迄今为止,我们所掌握的线程间通信手段还只限于主线程通过唤醒、中断机制向子线程发出信号,或者通过在创建子线程时向构造方法传入数据,以及设置子线程的公有属性值。在千变万化的应用需求面前,仅凭这些手段是难以胜任要求的。
在多线程开发领域,线程与线程之间经常需要交换信息,这是一种普遍存在的需求,并不仅限于主线程与子线程之间,子线程与子线程之间也很可能需要交换信息。
线程之间能够方便地基于共享地址空间实现通信,这本身便是多线程应用程序的一大优势,因为进程之间是不能互访对方的地址空间的,在进程之间传递信息只能采用类似于远程调用的手段。
本节介绍利用Java输入输出API中的内部管道(Pipe),在线程之间实现二进制信息和字符信息的传输。
7.3.1 传递二进制信息
利用 java.io.PipedOutputStream和java.io.PipedInputStream可以实现线程之间的二进制信息传输。 java.io.PipedOutputStream是java.io.OutputStream的直接子类,而java.io. PipedInputStream是java.io.InputStream的直接子类。
与OutputStream和 InputStream的最重要区别在于:PipedOutputStream拥有一个允许指定输入管道流的构造方法,而 PipedInputStream拥有一个允许指定输出管道流的构造方法。从而使得PipedOutputStream和 PipedInputStream往往成对出现、配合使用。
下面的例程演示利用java.io.PipedOutputStream和java.io.PipedInputStream在子线程thread1和thread2之间传递二进制信息。源代码如下。
代码清单7‑14 线程间通信的例程——CommunicationByPipeBytes
1. import java.io.PipedOutputStream;
2. import java.io.PipedInputStream;
3. import java.io.IOException;
4.
5. public class CommunicationByPipeBytes
6. {
7. static PipedOutputStream pos=null;
8. static PipedInputStream pis=null;
9.
10. public static void main(String[] args) throws IOException
11. {
12. pos=new PipedOutputStream();
13. pis=new PipedInputStream(pos);
14.
15. Thread thread1=new Thread()
16. {
17. public void run()
18. {
19. try
20. {
21. pos.write("hello".getBytes());
22. pos.flush();
23. }
24. catch(IOException ioe)
25. {
26. ioe.printStackTrace();
27. }
28. }
29. };
30. thread1.start();
31.
32. Thread thread2=new Thread()
33. {
34. public void run()
35. {
36. try
37. {
38. byte[] bytes=new byte[pis.available()];
39. pis.read(bytes,0,bytes.length);
40. System.out.println(new String(bytes));
41. }
42. catch(IOException ioe)
43. {
44. ioe.printStackTrace();
45. }
46. }
47. };
48. thread2.start();
49. }
50. }
线程thread1通过管道字节流向线程thread2传递字符串“hello”的字节。程序的运行结果是线程thread2在控制台上打印输出“hello”字样。
7.3.2 传递字符信息
本节介绍利用 java.io.PipedWriter和java.io.PipedReader在线程之间传输字符信息。与 java.io.PipedOutputStream和java.io.PipedInputStream类似,java.io.PipedWriter 是java.io.Writer的直接子类,java.io.PipedReader是java.io.Reader的直接子类。
与Writer和Reader的最重要区别在于,PipedWriter拥有一个允许指定输入管道字符流的构造方法,而PipedReader拥有一个允许指定输出管道字符流的构造方法。从而使得PipedWriter和PipedReader往往成对出现、配合使用。
下面的例程演示利用 java.io.PipedWriter和java.io.PipedReader在子线程thread1和thread2之间传递字符信息。为了读取字 符串的方便,本例程引入了java.io.BufferedWriter和java.io.BufferedReader。源代码如下。
代码清单7‑15 线程间通信的例程——CommunicationByPipeCharacters
1. import java.io.PipedWriter;
2. import java.io.PipedReader;
3. import java.io.BufferedWriter;
4. import java.io.BufferedReader;
5. import java.io.IOException;
6.
7. public class CommunicationByPipeCharacters
8. {
9. static PipedWriter pw=null;
10. static PipedReader pr=null;
11. static BufferedWriter bw=null;
12. static BufferedReader br=null;
13.
14. public static void main(String[] args) throws IOException
15. {
16. pw=new PipedWriter();
17. pr=new PipedReader(pw);
18. bw=new BufferedWriter(pw);
19. br=new BufferedReader(pr);
20.
21. Thread thread1=new Thread()
22. {
23. public void run()
24. {
25. try
26. {
27. bw.write("hello",0,"hello".length());
28. bw.newLine();
29. bw.flush();
30. }
31. catch(IOException ioe)
32. {
33. ioe.printStackTrace();
34. }
35. }
36. };
37. thread1.start();
38.
39. Thread thread2=new Thread()
40. {
41. public void run()
42. {
43. try
44. {
45. System.out.println(br.readLine());
46. }
47. catch(IOException ioe)
48. {
49. ioe.printStackTrace();
50. }
51. }
52. };
53. thread2.start();
54. }
55. }
线程thread1通过管道字符流向线程thread2传递字符串“hello”的字符。程序的运行结果是线程thread2在控制台上打印输出“hello”字样。