自己尝试把今天上午的学习整理一下,代码大部分是《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要调用这个函数。比较典型的系统钩子应用就是键盘钩子和鼠标钩子: HHOOK g_hHookKbd = NULL; HHOOK g_hHookMouse = NULL; 在Windows中,...
本资源摘要信息主要讲解了航测无人机的计划方案,包括航测无人机的优势、工作原理、飞行平台、飞控系统、地面监控系统、起降方式、安全性要求、照相设备等方面的内容。 一、航测无人机的优势 航测无人机相比传统...
因本人水平有限,程序做的不是很智能,稍为高手点的都可以出赢,本程序主要界面比较美观大方,友好.程序有详细注释,适合初学者研究.如果你对C#.NET也感兴趣,欢迎到我的百度空间或我的个人网站做客.最后附上我的个人网站...
现提供求职简历模板一份,程序员/工程师可通用,框架已用EXCEL编辑好,表格是我自己制作的,已经打包好,下下来直接填充下自己的姓名年龄等就OK,自信比网上下载的好,网上也下载不到我这样的,只需自己稍为添加自己...
这篇文档实际上是一份高二语文试卷,主要涉及的是古代汉语的知识点。以下是对试卷中部分内容的解析: 1. 字音题:考查了学生对汉字读音的掌握,例如"修葺(qì)"、"偃仰(yán)"、"湮没(yān)"、"缇骑(tí)"等...
两手掌向上握住横杠,两手间距比肩稍为宽些,两臂伸直支撑住杠铃位于胸的上部。 C.动作过程:使两直臂向两侧张开,两臂慢慢弯屈,杠铃垂直落下,直至横杠接触到胸部(大约接近乳头线上方)。然后向上推起至开设位置...
经过我稍为地改动一下,现在以上问题解决了特将修改后的文件复制一份,同大家分享只有三处修改uses 下面加上:StrUtils 一处,全文查找 AnsiReplaceStr便可找到另外两处frxClass.pas版本为kaida 2005-01-23 提供的3.09...
$ca = new cls_analysis();...$str = "输入一段稍为长一点的文本"; $ca->SetSource( $str, 'utf-8', 'utf-8'); $ca->StartAnalysis(); $keywords = $ca->GetFinallyKeywords( 10 ); //参数指定的是关键字提取的个数
3.将反射板的加强支架和反射板装在反射板托盘上,在反射板与反射板相联接时稍为固定即可暂不紧固,等全部装上后,调整板面平整再将全部螺丝坚固。 四、馈源、高频头的安装与调整 把馈源和高频头和连接其矩形波导口...
所以我做了一个稍为另类一点的,不用PAGECONTROL或TABCONTROL,而是用PANEL,另外再加一个IMAGE控件(用它来加载一个“关闭”按钮的图片) 效果如下: http://hi.csdn.net/attachment/201202/1/0_1328096680pBO0.gif...
什么是语义URL 攻击? 好奇心是很多攻击者的主要动机,语义URL 攻击就是一个很好的例子。...虽然对GET 数据的操纵只是比对POST 数据稍为方便,但它的暴露性决定了它更为频繁的受攻击,特别是对于攻击
总体来看,班级之间相差不大,以二班稍为突出,但总体成绩较好。各班优秀高分者少,90 分以上 5 人,80 分以上 37人,大部分学生的成绩集中在60-70 之间。 三、存在的主要问题 1. 学生对基础知识的掌握和理解不够...
免积分下载 Infix PDF Editor是一款方便...如果您急于修改PDF文件, 但又找不到原始文件, 或发现手中的PDF文件只要稍为改动或换掉图片就可以使用, 甚至想好像用文字编辑软件一样来编辑PDF, 这套软件就可以实现您的梦想。
Ghost密码破解 校验MD5 CRC32 SHA1 SHA256 说 明 ...2、若计算两个或以上HASH值,建议勾选[并行运算], 3、若勾选了[显示进度],计算过程可能会稍为变慢, 5、不要用本工具从事任何营利活动或任何违法活动。
员工必须严格遵守保密规定,不得泄露公司的商业秘密,包括经营策略、财务信息、经营成果等。经理层需定期对员工进行职业道德教育,强化保密意识。一旦发生违反保密规定的行为,公司将追究相关责任。 **结语** 外资...
$.support.style) { //代码 } jquery 判断浏览器方法 jquery中利用navigator.userAgent.indexOf来判断浏览器类型,并进行了一下处理,如果不想使用jquery,稍为修改下代码就可以为自己所用 jquery判断浏览器的源码...