`
feipigzi
  • 浏览: 111663 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

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

阅读更多

自己尝试把今天上午的学习整理一下,代码大部分是《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接口的方法
*/

 

分享到:
评论

相关推荐

    windows编程资料大全

    Windows中的钩子实际上是一个回调函数,当用户有输入动作的时候,Windows要调用这个函数。比较典型的系统钩子应用就是键盘钩子和鼠标钩子: HHOOK g_hHookKbd = NULL; HHOOK g_hHookMouse = NULL; 在Windows中,...

    航测无人机计划方案讲解.pdf

    本资源摘要信息主要讲解了航测无人机的计划方案,包括航测无人机的优势、工作原理、飞行平台、飞控系统、地面监控系统、起降方式、安全性要求、照相设备等方面的内容。 一、航测无人机的优势 航测无人机相比传统...

    人机对战-极品五子棋

    因本人水平有限,程序做的不是很智能,稍为高手点的都可以出赢,本程序主要界面比较美观大方,友好.程序有详细注释,适合初学者研究.如果你对C#.NET也感兴趣,欢迎到我的百度空间或我的个人网站做客.最后附上我的个人网站...

    JAVA EE工程师/程序员求职简历

    现提供求职简历模板一份,程序员/工程师可通用,框架已用EXCEL编辑好,表格是我自己制作的,已经打包好,下下来直接填充下自己的姓名年龄等就OK,自信比网上下载的好,网上也下载不到我这样的,只需自己稍为添加自己...

    高二语文试卷高中语文第三册第六单元测试A[精选].doc

    这篇文档实际上是一份高二语文试卷,主要涉及的是古代汉语的知识点。以下是对试卷中部分内容的解析: 1. 字音题:考查了学生对汉字读音的掌握,例如"修葺(qì)"、"偃仰(yán)"、"湮没(yān)"、"缇骑(tí)"等...

    史上最全室内健身器械使用方法%28带图片啊.doc

    两手掌向上握住横杠,两手间距比肩稍为宽些,两臂伸直支撑住杠铃位于胸的上部。 C.动作过程:使两直臂向两侧张开,两臂慢慢弯屈,杠铃垂直落下,直至横杠接触到胸部(大约接近乳头线上方)。然后向上推起至开设位置...

    fastreport3合计处理不好修正

    经过我稍为地改动一下,现在以上问题解决了特将修改后的文件复制一份,同大家分享只有三处修改uses 下面加上:StrUtils 一处,全文查找 AnsiReplaceStr便可找到另外两处frxClass.pas版本为kaida 2005-01-23 提供的3.09...

    PHP简易中文分词

    $ca = new cls_analysis();...$str = "输入一段稍为长一点的文本"; $ca-&gt;SetSource( $str, 'utf-8', 'utf-8'); $ca-&gt;StartAnalysis(); $keywords = $ca-&gt;GetFinallyKeywords( 10 ); //参数指定的是关键字提取的个数

    卫星电视安装调试指南_新手必读资料.pdf

    3.将反射板的加强支架和反射板装在反射板托盘上,在反射板与反射板相联接时稍为固定即可暂不紧固,等全部装上后,调整板面平整再将全部螺丝坚固。 四、馈源、高频头的安装与调整 把馈源和高频头和连接其矩形波导口...

    DELPHI 用PANEL当窗体标签

    所以我做了一个稍为另类一点的,不用PAGECONTROL或TABCONTROL,而是用PANEL,另外再加一个IMAGE控件(用它来加载一个“关闭”按钮的图片) 效果如下: http://hi.csdn.net/attachment/201202/1/0_1328096680pBO0.gif...

    PHP中通过语义URL防止网站被攻击的方法分享

    什么是语义URL 攻击? 好奇心是很多攻击者的主要动机,语义URL 攻击就是一个很好的例子。...虽然对GET 数据的操纵只是比对POST 数据稍为方便,但它的暴露性决定了它更为频繁的受攻击,特别是对于攻击

    九年级道德与法治上学期期末试卷分析-6页.pdf

    总体来看,班级之间相差不大,以二班稍为突出,但总体成绩较好。各班优秀高分者少,90 分以上 5 人,80 分以上 37人,大部分学生的成绩集中在60-70 之间。 三、存在的主要问题 1. 学生对基础知识的掌握和理解不够...

    Infix PDF Editor 6.4.6 破解版 0分

    免积分下载 Infix PDF Editor是一款方便...如果您急于修改PDF文件, 但又找不到原始文件, 或发现手中的PDF文件只要稍为改动或换掉图片就可以使用, 甚至想好像用文字编辑软件一样来编辑PDF, 这套软件就可以实现您的梦想。

    Ghost密码查看

    Ghost密码破解 校验MD5 CRC32 SHA1 SHA256 说 明 ...2、若计算两个或以上HASH值,建议勾选[并行运算], 3、若勾选了[显示进度],计算过程可能会稍为变慢, 5、不要用本工具从事任何营利活动或任何违法活动。

    外资外企公司员工工作制度上班制度【精品模板】..doc

    员工必须严格遵守保密规定,不得泄露公司的商业秘密,包括经营策略、财务信息、经营成果等。经理层需定期对员工进行职业道德教育,强化保密意识。一旦发生违反保密规定的行为,公司将追究相关责任。 **结语** 外资...

    Jquery判断IE6等浏览器的代码

    $.support.style) { //代码 } jquery 判断浏览器方法 jquery中利用navigator.userAgent.indexOf来判断浏览器类型,并进行了一下处理,如果不想使用jquery,稍为修改下代码就可以为自己所用 jquery判断浏览器的源码...

Global site tag (gtag.js) - Google Analytics