回调思想(稍为涉及线程、摘要信息)

自己尝试把今天上午的学习整理一下,代码大部分是《java网络编程》中的源码,自己做了一点点修改,本文涉及主要类和接口有 Thread、Runnable、DigestInputStream、FileInputStream、MessageDigest等

 

程序主要有两个部分:线程中获得文件摘要信息  和  用户打印这些信息

 

使用简单的存取方法获得线程输出

使用存取方法返回线程结果:

ReturnDigest :

 

public class ReturnDigest extends Thread {

	private File input;
	private byte[] digest;

	public ReturnDigest(File input) {
		this.input = input;
	}

	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();
			digest = sha.digest();
//			System.out.println(digest);
		} catch (IOException ex) {
			System.err.println(ex);
		} catch (NoSuchAlgorithmException ex) {
			System.err.println(ex);
		}
	}
	
	public byte[] getDigest(){

		return digest;
	}
}

 

使用存取方法获得线程输出:

ReturnDigestUserInterface :

public class ReturnDigestUserInterface {

	public static void main(String[] args) throws InterruptedException {
		String[] strArray = new String[] { "a.txt", "b.txt", "c.txt" };
		for (String str : strArray) {
			//计算摘要
			File f = new File(str);
			ReturnDigest dr = new ReturnDigest(f);
			dr.start();

			//显示信息
			StringBuffer result = new StringBuffer(f.toString());
			result.append(": ");
//			while(dr.getDigest() == null);
			byte[] digest = dr.getDigest();
			for(int i = 0; i < digest.length; i++){
				result.append(digest[i] + " ");
			}
			System.out.println(result);
		}
	}
}

    以上两段代码作为背景,只为说明了程序的目的,含有很多缺陷,例如 主程序中, dr.getDigest(); 返回的可能是一个null对象,因为线程中获得digest的代码还没跑完。

 

轮询

新手使用较多(我之前也是这么干的,呵呵)

//可以像代码中注释,使用
while(dr.getDigest() == null);

//或者
while(true){
	get
	if(!null)
		print
}

 

回调

轮询浪费太多的cpu时间了!

 

这里使用回调思想,总体思想是:主程序中不再直接获得线程信息然后处理,而是线程获得信息后,回调给用户接口类。

(第一次接触这种思想是在学习awt的时候,第一次应用是在写一个贪吃蛇游戏的时候)

 

以下循环渐进,介绍几种利用了回调思想的方法

 

 

静态回调:

CallbackDigest :

public class CallbackDigest implements Runnable {

	private File input;

	public CallbackDigest(File input) {
		this.input = input;
	}

	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();
			// 这里没有返回信息,而是完成后,回调(触发)用户类方法
			CallbackDigestUserInterface.receiveDigest(digest, input.getName());
		} catch (IOException ex) {
			System.err.println(ex);
		} catch (NoSuchAlgorithmException ex) {
			System.err.println(ex);
		}
	}
}

 

CallbackDigestUserInterface :

 

import java.io.File;

public class CallbackDigestUserInterface {
	//这里receiveDIgest()没有放在主线程,而是由每个线程单独调用
	public static void receiveDigest(byte[] digest, String name) {
		 
		StringBuffer result = new StringBuffer(name);
		result.append(": ");
		for (int i = 0; i < digest.length; i++) {
			result.append(digest[i] + " ");
		}
		System.out.println(result);
	}
	
	public static void main(String[] args) {
		
		String[] strArray = new String[]{"a.txt","b.txt","c.txt"};
		for(String str : strArray){
			File f = new File(str);
			CallbackDigest cb = new CallbackDigest(f);
			Thread t = new Thread(cb);
			t.start();
		}
	}
}

 主程序中 构造CallbackDigest 实例并创建、启动线程,run()方法中,获得摘要信息digest后,直接调用用户类CallbackDigestUserInterface 的 receiveDigest() 方法,这样轻松实现了程序功能,同时避免了 “轮询” ,节省cpu时间。

 实例方法回调:

InstanceCallbackDigest :

public class InstanceCallbackDigest implements Runnable {

	private File input;

	private InstanceCallbackDigestUserInterface callback;

	public InstanceCallbackDigest(File input,
			InstanceCallbackDigestUserInterface callback) {
		this.input = input;
		this.callback = callback;
	}

	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();
			callback.receiveDigest(digest);
		} catch (IOException ex) {
			System.err.println(ex);
		} catch (NoSuchAlgorithmException ex) {
			System.err.println(ex);
		}
	}
}

 

InstanceCallbackDigestUserInterface :

public class InstanceCallbackDigestUserInterface {

	private File input;
	private byte[] digest;

	public InstanceCallbackDigestUserInterface(File input) {
		this.input = input;
	}

	public void calculateDigest() {
		InstanceCallbackDigest cb = new InstanceCallbackDigest(input, this);
		Thread t = new Thread(cb);
		t.start();
	}

	void receiveDigest(byte[] digest){
		this.digest = digest;
		System.out.println(this);
	}
	
	public String toString(){
		String result = input.getName() + ": ";
		if(digest != null){
			for(int i = 0; i < digest.length; i++){
				result += digest[i] + " ";
			}
		}
		else{
			result = " digest not available";
		}
		return result;
	}
	
	public static void main(String[] args) {
		String[] strArray = new String[]{"a.txt","b.txt","c.txt"};
		for(String str : strArray){
			File f = new File(str);
			InstanceCallbackDigestUserInterface d = new InstanceCallbackDigestUserInterface(f);
			d.calculateDigest();
		}
	}
}

     相对之前的静态回调,摘要类InstanceCallbackDigest 多了一个InstanceCallbackDigestUserInterface 类成员 callback 。主程序 构造InstanceCallbackDigestUserInterface 实例(文件参数),调用calculateDigest()方法,该方法中利用构造了摘要类InstanceCallbackDigest 实例(用户类参数 user,文件参数),并创建、启动线程,run()方法中获得摘要后,调用user的 receiveDigest()方法,该方法打印了信息。

    实例方法相对复杂一些,优点:每个主类InstanceCallbackDigest 映射一个File文件,用户接口类不需要额外的数据结构去获得文件的信息。而且,这个实例必要时可以重新计算某个文件的摘要,相当灵活,这种设计方法经常被使用。

 

回调对象列表:

如果关心摘要信息的用户接口类不只是一个呢?可以可以利用一个列表对象保存 所有 关心线程中获得的摘要信息 的用户接口实例,所有的这些用户接口实例 都要实现同一个接口,该接口声明了如何处理摘要信息的方法。

 

接口DigestListener : 

public interface DigestListener {
	
	//回调:处理线程中获得的digest信息
	public void digestHandle(byte[] digest);
}

 

 

ListCallbackDigest :

public class ListCallbackDigest implements Runnable {

	private File input;
	List listenerList = new Vector();
	
	public ListCallbackDigest(File input){
		this.input = input;
	}
	
	public synchronized void addDigestListener(DigestListener l) {
		listenerList.add(l);
	}
	
	public synchronized void removeDigestListener(DigestListener l) {
		listenerList.remove(l);
	}
	
	private synchronized void sendDigest(byte[] digest){
		
		Iterator iterator = listenerList.listIterator();
		while(iterator.hasNext()){
			DigestListener dl = (DigestListener) iterator.next();
			dl.digestHandle(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 (IOException ex) {
			System.err.println(ex);
		}
		catch(NoSuchAlgorithmException ex){
			System.err.println(ex);
		}
	}
	
}

 

ListCallbackDigestUserInterface :

public class ListCallbackDigestUserInterface implements DigestListener {

	private File input;
	private byte[] digest;

	public ListCallbackDigestUserInterface(File input) {
		this.input = input;
	}

	public void calculateDigest() {
		ListCallbackDigest cb = new ListCallbackDigest(input);
		cb.addDigestListener(this);
		Thread t = new Thread(cb);
		t.start();
	}

	public void digestHandle(byte[] digest) {
		this.digest = digest;
		System.out.println(this);
	}

	public String toString() {
		String result = input.getName() + ": ";
		if (digest != null) {
			for (int i = 0; i < digest.length; i++) {
				result += digest[i] + " ";
			}
		}
		else {
			result = " digest not available";
		}
		return result;
	}
	
	public static void main(String[] args) {
		String[] strArray = new String[]{"a.txt","b.txt","c.txt"};
		for(String str : strArray){
			File f = new File(str);
			ListCallbackDigestUserInterface d = new ListCallbackDigestUserInterface(f);
			d.calculateDigest();
		}
	}

}

 主程序中,构造了用户接口实例,用户调用calculateDigest()方法,该方法构造摘要类ListCallbackDigest 实例,向其中注册监听对象(这里只add了一个,可以add多个),然后创建并启动线程,run()中获得摘要digest后,也不是立刻跟监听的用户通信,而是调用一个sendDigest()方法,该方法遍历摘要类的成员(注册的监听用户对象列表),在循环中调用各自的digestHandle()方法(实现接口的方法)。

 

/*
com.yong.thread
	ReturnDigestThread	返回进程中的信息	
	ReturnDigestUserInterface 处理进程返回的信息
	
	CallbackDigest		与下者配合,实现回调,主方法中构造该类实例,并启动,run中实现静态回调
	CallbackDigestUserInterface	静态回调方法	
		
	InstanceCallbackDigest	实现Runnable接口,run中实现计算并回调给用户(下者)
	InstanceCallbackDigestUserInterface 实例用户接口对象,调用计算方法,计算方法里里面构造上者线程并启动(前面的静态回调是构造的实例不同哦)
	
	DigestListener	声明了回调方法的接口
	ListCallbackDigest	含有一个列表成员,存储需要需要回调的监听用户(该用户实现了DigestListener接口),
		回调的方式不在直接跟监听用户通信,而是用一个sendDigest的方法,遍历列表成员,调用它们实现的接口方法
	ListCallbackDigestUserInterface	实现了DigestListener的接口
	整个过程就是,实例ListCallbackDigest,增加监听对象,启动线程,run中取得摘要信息后,调用sendDigest()方法,里面遍历监听列表中的每个监听用户对象
	调用各自实现DigestListener接口的方法
*/

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值