4.2通讯服务模块线程之间传递信息 信息工程系 向模军 Tel: Email: QQ: 13684285460 xmj.cn@163.com 156638267
1 任务引入 线程之间不是孤立的,线程之间往往要进行信息交换,由于信息的多样性,对不同信息的处理方式是不同的,通常在基于TCP的聊天通讯过程中,通信信息被封装在一个消息对象中,要实现消息对象在网络上的传输,该消息类必须能够被“序列化”。监听线程在接收到消息对象后,将消息对象交给一个服务线程处理,服务线程根据消息对象的分类,有两种处理方式,对“命令类”消息,服务线程直接处理,对“聊天消息”,服务线程做日志记录,并将该消息对象添加到一个消息对象队列中,消息接收线程从消息对象队列中取出消息对象,并做相应的处理。 2/17
2 任务讨论 用于线程间传递信息的中间类设计;如何传递中间类。 3/17
3 对象流 对象的持续性(Persistence) 能够纪录自己的状态以便将来再生的能力,叫对象的持续性。对象的持续性通常应用在网络传输、介质存储等方面。对象的持续性通过串行化完成。 对象的串行化(Serialization) 对象通过写出描述自己状态的的数值来记录自己的过程叫串行化。串行化的主要任务是写出对象实例变量的数值,如果变量是另一个对象的引用,则引用的对象也要串行化。这个过程是递归的。 对象流概念 能够输入输出对象的流称为对象流。可以将对象串行化后通过对象输入输出流写入文件或传送到其它地方。 4/17
3 用管道流实现线程间的通信 管道用来把一个程序、线程和代码块的输出连接到另一个程序、线程和代码块的输入。java.io中提供了类PipedInputStream和PipedOutputStream作为管道的输入/输出流。 线程1 PipedOutputStream PipedInputStream 输出流outStream 输入流inStream 线程2 主类Pipethread 辅类myWriter 线 程 类 辅类 myReader 管 道 流 将数据写到输出流 从输入流中读数据 输出流作为参数 传给myWriter 输入流作为参数 传给myReader 5/17
3 用管道流实现线程间的通信 写线程 6/17 import java.io.*; class myWriter extends Thread { private PipedOutputStream outStream; //将数据输出 private String messages[] = {"Monday", "Tuesday ", "Wednsday", "Thursday", "Friday", "Saturday", "Sunday"}; public myWriter(PipedOutputStream o) { outStream = o; } public void run() { try { ObjectOutputStream p = new ObjectOutputStream(outStream); for (int i = 0; i < messages.length; i++) { System.out.println("Write:" + messages[i]); p.writeObject(messages[i]); p.flush(); p.close(); p = null; } catch (IOException e) {} 写线程 6/17
3 用管道流实现线程间的通信 读线程 7/17 import java.io.*; class myReader extends Thread { private PipedInputStream inStream; //从中读数据 public myReader(PipedInputStream i) { inStream = i; } public void run() { Object data; ObjectInputStream r; boolean reading = true; try { r = new ObjectInputStream(inStream); while (reading && r != null) { data = r.readObject(); if (data != null) { System.out.println("Read: " + data.toString()); } else { reading = false; r.close(); } catch (IOException e) {} catch (ClassNotFoundException e) {} 读线程 7/17
3 用管道流实现线程间的通信 利用管道流的主线程 8/17 import java.io.*; public class Pipethread { public static void main(String args[]) { Pipethread thisPipe = new Pipethread(); thisPipe.process(); } public void process() { PipedInputStream inStream; PipedOutputStream outStream; try{ outStream = new PipedOutputStream(); inStream = new PipedInputStream(outStream); new myWriter( outStream ).start(); new myReader( inStream ).start(); }catch( IOException e ){ } 利用管道流的主线程 8/17
3 通过一个中间类在线程间传递信息 线程2 线程1 中间类m s m.write(s) s=m.read() write() read() 管道流方式自动解决了写线程和读线程之间的互斥共享问题,而自己定义的中间类必须自己解决写线程和读线程之间的互斥共享问题。 9/17
3 通过一个中间类在线程间传递信息 中间类 10/17 public class shareObject { private String value=""; public shareObject() { } public void write(String str){this.value=str;} public String read(){return this.value;} } 中间类 10/17
3 通过一个中间类在线程间传递信息 写线程 11/17 class myWriter extends Thread { private shareObject obj = null; private String messages[] = {"Monday", "Tuesday ", "Wednsday", "Thursday","Friday", "Saturday", "Sunday"}; public myWriter(shareObject obj) { this.obj = obj; } public void run() { try {for (int i = 0; i < messages.length; i++) { System.out.println("Write:" + messages[i]); obj.write(messages[i]); sleep( 400); } } catch (InterruptedException e) {} obj.write("end"); System.out.println("写线程结束"); 写线程 11/17
3 通过一个中间类在线程间传递信息 读线程 12/17 public class myReader extends Thread { private shareObject obj = null; public myReader(shareObject obj) { this.obj = obj; } public void run() { try {String value = obj.read(); while (!value.trim().equals("end")) { if (value.trim().length() > 0) System.out.println("Reader:" + value); sleep(500); value=obj.read(); } } catch (InterruptedException e) {} System.out.println("读线程结束"); 读线程 12/17
4 任务实施 在JBuilder中新建项目。在项目中建立以下6个类。 TransData类:用于网络传输的“消息”,序列化。 DataCache类:“消息队列”,存储需要处理的TransData实例。 listenThread线程类:模拟网络通讯,不断接收不同类型的“消息”,并创建、启动serviceThread线程处理接收到的“消息”。 serviceThread线程类:处理comand型的“消息”,将其他“消息”加入“消息队列”。 messageManager线程类:处理“消息队列”中的“消息”。 mainThread类:主程序,启动listenThread和mesageManager线程。 13/17
5 任务点评 messageManager是单线程,与listenThread线程一起启动。 serviceThread是多线程, listenThread每产生一个“消息”,就创建并启动一个serviceThread线程。 DataCache是一个中间类,负责messageManager线程与serviceThread线程之间传递信息。 14/17
6 试一试 练一练 试改写DataCache,使messageManager线程在读取“消息队列”期间被“阻塞”一会儿。观察程序输出有何变化。 15/17
7 课外拓展 收集资料,了解“对象的持续性 ”应用环境。 16/17
Thank You !