从结束的线程中返回信息,注意到run()方法和start()方法不返回任意值。可以用‘回调’实现!
案例如下(详见Java网络编程3th):
package callback;
/*
* 如何获得线程输出?
* 1.直接使用存取方法如get()获得线程输出,这种方法会由于主线程和其它线程步调不一致,
* 主函数中使用线程中返回的对象时,可能此时对象还未在线程中完成初始化.
* 可以使用轮询(while(xxx!=null))测试.
* 2.回调.当线程的run方法接近结束时,基于结果调用主类中的一个已知方法,
* 可以是调用主类的静态方法也可以在线程中用主类的实例(线程类持有,可以通过构造函数传入)调用实例方法.
* 回调机制可以处理涉及更多线程、对象和类更加复杂的情况.
* 例如有多个对象关心线程的计算结果,那么线程可以持有一个回调对象列表.
* 某个对象通过调用Thread或者Runnable类的一个方法把自己添加到列表中表示自己对计算结果关注.
* #如果有多个类的实例关心结果,可以定义一个interface(接口),让所有这些类都实现这个接口.
* #下面的DigestListener接口就是这样一个例子
*/
public interface DigestListener {
//此接口声明了digestCalculated方法,此方法将作为线程中的回调方法
public void digestCalculated(byte[] digest);
}
package callback;
import java.io.*;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;
/*
* 计算文件摘要的Runnable类
*/
public class ListcallBackDigest implements Runnable {
private File input;//文件源
List listennerList=new Vector();//存放回调对象的列表
public ListcallBackDigest(File input){
this.input=input;
}
//-------向回调对象的列表中添加对象(实现了DigestListener接口的)---------
public synchronized void addDigestListenner(DigestListener l){
listennerList.add(l);
}
public synchronized void removeDigestListenner(DigestListener l){
listennerList.remove(l);
}
//----------------向列表中存的所有回调对象发送回调请求-----------------
private synchronized void sendDigest(byte[] digest){
ListIterator itrator=listennerList.listIterator();
while(itrator.hasNext()){
DigestListener dl=(DigestListener) itrator.next();
//为每一个回调对象调用回调函数,从线程向目标对象返回信息,本例中的目标对象主要完成文件摘要的计算
dl.digestCalculated(digest);
}
}
public void run() {
try {
FileInputStream in=new FileInputStream(input);
MessageDigest sha=MessageDigest.getInstance("SHA");
DigestInputStream din=new DigestInputStream(in, sha);
int b;
while((b=din.read())!=-1);//不断读取
din.close();
byte[] digest=sha.digest();
this.sendDigest(digest);//线程的最后调用回调方法,传回信息
} catch (Exception e) {
e.printStackTrace();
}
}
}
package callback;
import java.io.*;
public class UserInterface implements DigestListener{
public static long beginTime ;
private File input;
private byte[] digest;//保存线程传回来的数据
public UserInterface(File input){
this.input=input;
}
//--------实际启动线程的方法------------
public void calculatDigest(int i){
ListcallBackDigest lcb=new ListcallBackDigest(input);
lcb.addDigestListenner(this);//添加当前对象
Thread t=new Thread(lcb);
t.setName("线程"+(i+1));
t.start();
}
@Override
//------------回调的方法-------------
public void digestCalculated(byte[] digest) {
// TODO Auto-generated method stub
this.digest=digest;
System.out.print(this);//下面要重写该类的ToString方法
long endTime = System.currentTimeMillis();//记录当前系统时间
System.out.println(Thread.currentThread().getName()+":"+"耗时 "+(endTime-beginTime)/1000+"秒");
}
public String toString(){
String res=input.getName()+":";
if(digest!=null){
for(int i=0;i<digest.length;i++){
res+=digest[i]+" ";
}
}else
res+="digest not available!";
return res;
}
//-------------主函数---------------
public static void main(String[] args) {
beginTime = System.currentTimeMillis();//记录当前系统时间
for(int i=0;i<args.length;i++){
File f=new File(args[i]);
UserInterface u=new UserInterface(f);
u.calculatDigest(i);
}
System.out.println("main()结束!");
}
}
原文地址:http://blog.csdn.net/hellozpc/article/details/42031631