Java线程间通信-回调的实现方式
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.DigestInputStream;
/**
* 求文件的信息摘要码(MD5)
*
* @author leizhimin 2008-9-11 22:53:39
*/
public class CallbackDigest implements Runnable {
private File inputFile; //目标文件
public CallbackDigest(File input) {
this.inputFile = input;
}
public void run() {
try {
FileInputStream in = new FileInputStream(inputFile);
MessageDigest sha = MessageDigest.getInstance("MD5");
DigestInputStream din = new DigestInputStream(in, sha);
int b;
while ((b = din.read()) != -1) ;
din.close();
byte[] digest = sha.digest(); //摘要码
//完成后,回调主线程静态方法,将文件名-摘要码结果传递给住线程
CallbackDigestUserInterface.receiveDigest(digest, inputFile.getName());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 静态非同步回调
*
* @author leizhimin 2008-9-11 23:00:12
*/
public class CallbackDigestUserInterface {
/**
* 接收摘要码,输出到控制台
*
* @param digest 摘要码
* @param inputFileName 输入的文件名
*/
public static void receiveDigest(byte[] digest, String inputFileName) {
StringBuffer result = new StringBuffer(inputFileName);
result.append(": ");
for (int j = 0; j < digest.length; j++) {
result.append(digest[j] + " ");
}
System.out.println(result);
}
public static void main(String[] args) {
String arr[] = {"C:\\xcopy.txt", "C:\\x.txt", "C:\\xb.txt", "C:\\bf2.txt"};
args = arr;
for (int i = 0; i < args.length; i++) {
File f = new File(args[i]);
CallbackDigest cb = new CallbackDigest(f);
Thread t = new Thread(cb);
t.start();
}
}
}
xb.txt: 112 -81 113 94 -65 -101 46 -24 -83 -55 -115 18 -1 91 -97 98
x.txt: 123 -91 90 -16 -116 -94 -29 -5 -73 25 -57 12 71 23 -8 -47
xcopy.txt: 123 -91 90 -16 -116 -94 -29 -5 -73 25 -57 12 71 23 -8 -47
Process finished with exit code 0
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.DigestInputStream;
/**
* 求文件的信息摘要码(MD5)
*
* @author leizhimin 2008-9-11 22:53:39
*/
public class InstanceCallbackDigest implements Runnable {
private File inputFile; //目标文件
//每个线程绑定一个回调对象
private InstanceCallbackDigestUserInterface instanceCallback;
/**
* 构件时一次注入回调对象
*
* @param instanceCallback
* @param inputFile
*/
public InstanceCallbackDigest(InstanceCallbackDigestUserInterface instanceCallback, File inputFile) {
this.instanceCallback = instanceCallback;
this.inputFile = inputFile;
}
public void run() {
try {
FileInputStream in = new FileInputStream(inputFile);
MessageDigest sha = MessageDigest.getInstance("MD5");
DigestInputStream din = new DigestInputStream(in, sha);
int b;
while ((b = din.read()) != -1) ;
din.close();
byte[] digest = sha.digest(); //摘要码
//完成后,回调主线程静态方法,将文件名-摘要码结果传递给住线程
instanceCallback.receiveDigest(digest);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 静态非同步回调
*
* @author leizhimin 2008-9-11 23:00:12
*/
public class InstanceCallbackDigestUserInterface {
private File inputFile; //回调与每个文件绑定
private byte digest[]; //文件的消息摘要码
public InstanceCallbackDigestUserInterface(File inputFile) {
this.inputFile = inputFile;
}
/**
* 计算某个文件的消息摘要码
*/
public void calculateDigest() {
InstanceCallbackDigest callback = new InstanceCallbackDigest(this, inputFile);
Thread t = new Thread(callback);
t.start();
}
/**
* 接收消息摘要码
*
* @param digest
*/
public void receiveDigest(byte[] digest) {
this.digest = digest;
//将消息摘要码输出到控制台实际上执行的是this.toString()方法
System.out.println(this);
}
/**
* 显示结果
*
* @return 结果
*/
public String toString() {
String result = inputFile.getName() + ": ";
if (digest != null) {
for (byte b : digest) {
result += b + " ";
}
} else {
result += "digest 不可用!";
}
return result;
}
public static void main(String[] args) {
String arr[] = {"C:\\xcopy.txt", "C:\\x.txt", "C:\\xb.txt", "C:\\bf2.txt"};
args = arr;
for (int i = 0; i < args.length; i++) {
File f = new File(args[i]);
InstanceCallbackDigestUserInterface cb = new InstanceCallbackDigestUserInterface(f);
cb.calculateDigest();
}
}
}
x.txt: 123 -91 90 -16 -116 -94 -29 -5 -73 25 -57 12 71 23 -8 -47
xb.txt: 112 -81 113 94 -65 -101 46 -24 -83 -55 -115 18 -1 91 -97 98
bf2.txt: 31 -37 46 -53 -26 -45 36 -105 -89 124 119 111 28 72 74 112
Process finished with exit code 0
calculateDigest()方法,这个方法可能在逻辑上认为它属于一个构造器。然而,在构造器中启动线程是相当危险的,特别是对开始对象回调的线
程。这里存在一个竞争条件:构造器中假如有很多的事情要做,而启动新的线程先做了,计算完成了后要回调,可是这个时候这个对象还没有初始化完成,这样就产
生了错误。当然,实际中我还没有发现这样的错误,但是理论上是可能的。 因此,避免从构造器中启动线程是一个明智的选择。
* 回调接口
*
* @author leizhimin 2008-9-13 17:20:11
*/
public interface DigestListener {
public void digestCalculated(byte digest[]);
}
* Created by IntelliJ IDEA.
*
* @author leizhimin 2008-9-13 17:22:00
*/
public class ListCallbackDigest implements Runnable {
private File inputFile;
private List<DigestListener> listenerList = Collections.synchronizedList(new ArrayList<DigestListener>());
public ListCallbackDigest(File inputFile) {
this.inputFile = inputFile;
}
public synchronized void addDigestListener(DigestListener ler) {
listenerList.add(ler);
}
public synchronized void removeDigestListener(DigestListener ler) {
listenerList.remove(ler);
}
private synchronized void sendDigest(byte digest[]) {
for (DigestListener ler : listenerList) {
ler.digestCalculated(digest);
}
}
public void run() {
try {
FileInputStream in = new FileInputStream(inputFile);
MessageDigest sha = MessageDigest.getInstance("MD5");
DigestInputStream din = new DigestInputStream(in, sha);
int b;
while ((b = din.read()) != -1) ;
din.close();
byte[] digest = sha.digest(); //摘要码
//完成后,回调主线程静态方法,将文件名-摘要码结果传递给住线程
System.out.println(digest);
this.sendDigest(digest);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
* Created by IntelliJ IDEA.
*
* @author leizhimin 2008-9-13 17:35:20
*/
public class ListCallbackDigestUser implements DigestListener{
private File inputFile; //回调与每个文件绑定
private byte digest[]; //文件的消息摘要码
public ListCallbackDigestUser(File inputFile) {
this.inputFile = inputFile;
}
/**
* 计算某个文件的消息摘要码
*/
public void calculateDigest() {
ListCallbackDigest callback = new ListCallbackDigest(inputFile);
Thread t = new Thread(callback);
t.start();
}
public void digestCalculated(byte digest[]) {
this.digest = digest;
//将消息摘要码输出到控制台实际上执行的是this.toString()方法
System.out.println(this);
}
/**
* 显示结果
*
* @return 结果
*/
public String toString() {
String result = inputFile.getName() + ": ";
if (digest != null) {
for (byte b : digest) {
result += b + " ";
}
} else {
result += "digest 不可用!";
}
return result;
}
public static void main(String[] args) {
String arr[] = {"C:\\xcopy.txt", "C:\\x.txt", "C:\\xb.txt", "C:\\bf2.txt"};
args = arr;
for (int i = 0; i < args.length; i++) {
File f = new File(args[i]);
ListCallbackDigestUser cb = new ListCallbackDigestUser(f);
cb.calculateDigest();
}
}
}
Java线程间通信-回调的实现方式的更多相关文章
- Java线程间通信之wait/notify
Java中的wait/notify/notifyAll可用来实现线程间通信,是Object类的方法,这三个方法都是native方法,是平台相关的,常用来实现生产者/消费者模式.我们来看下相关定义: w ...
- java线程间通信:一个小Demo完全搞懂
版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...
- 说说Java线程间通信
序言 正文 [一] Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在 ...
- 说说 Java 线程间通信
序言 正文 一.Java线程间如何通信? 线程间通信的目标是使线程间能够互相发送信号,包括如下几种方式: 1.通过共享对象通信 线程间发送信号的一个简单方式是在共享对象的变量里设置信号值:线程A在一个 ...
- Java——线程间通信
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- VC 线程间通信的三种方式
1.使用全局变量(窗体不适用) 实现线程间通信的方法有很多,常用的主要是通过全局变量.自定义消息和事件对象等来实现的.其中又以对全局变量的使用最为简洁.该方法将全局变量作为线程监视的对象,并通 ...
- 【转】VC 线程间通信的三种方式
原文网址:http://my.oschina.net/laopiao/blog/94728 1.使用全局变量(窗体不适用) 实现线程间通信的方法有很多,常用的主要是通过全局变量.自定义消息和 ...
- 线程间通信的三种方式(NSThread,GCD,NSOperation)
一.NSThread线程间通信 #import "ViewController.h" @interface ViewController ()<UIScrollViewDel ...
- java线程间通信1--简单实例
线程通信 一.线程间通信的条件 1.两个以上的线程访问同一块内存 2.线程同步,关键字 synchronized 二.线程间通信主要涉及的方法 wait(); ----> 用于阻塞进程 noti ...
随机推荐
- [Irving] Ext.Net动态添加GridPanel列绑定Checkbox值失败的解决办法
var grid = X.GetCmp<GridPanel>(vm.GRID_QUOTATIONS_FEEITEM_RANGE_SHOW); grid.AddColumn(Html.X() ...
- C++类型引用浅析
C++类型引用浅析 引言 从最早被Bjarne Stroustrup 发明,作为C语言的扩展,到广为人知C++98标准,再到最新的C++11.C++14和C++17标准,C++一直在不断地进步.演化. ...
- UVALive-4287 Proving Equivalences 有向图的强连通分量+缩点
题意:有n个命题,已知其中的m个推导,要证明n个命题全部等价(等价具有传递性),最少还需要做出几次推导. 思路:由已知的推导可以建一张无向图,则问题变成了最少需要增加几条边能使图变成强连通图.找出所有 ...
- android获取屏幕分辨率
DisplayMetrics dm = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(dm); dm. ...
- UVa10534 - Wavio Sequence(LIS)
题目大意 给定一个长度为n的整数序列,求个最长子序列(不一定连续),使得该序列的长度为奇数2k+1,前k+1个数严格递增,后k+1个数严格递减.注意,严格递增意味着该序列中的两个相邻数不能相同.n&l ...
- chroot 命令实例讲解
我是一个刚接触 Linux 和 Unix 的新手.我该如何改变一个命令的根目录?我要怎样改变一个进程的根目录呢,比如用 chroot 命令将web服务与文件系统隔离?我要如何使用 chroot 恢复密 ...
- Redis指令文档
连接控制QUIT 关闭连接AUTH (仅限启用时)简单的密码验证 适合全体类型的命令EXISTS key 判断一个键是否存在;存在返回 1;否则返回0;DEL key 删除某个key,或是一系列key ...
- 用普通PC主板的蜂鸣器给树莓派(RPI)加个报警器
这两天有点时间,捣鼓了下那闲置好久的树莓派,把普通PC主板的蜂鸣器作为树莓派的报警器用. Raspberry Pi有许多的GPIO(General Purpose Input Output:通用输入/ ...
- 【JAVA - SSM】之MyBatis动态SQL
动态SQL就是在SQL语句中添加一些标签,以完成某些逻辑.通常用到的动态SQL标签有<if>.<choose>.<where>.<trim>.<s ...
- spring getbean 方法分析
spring 缺省: 1.spring用DefaultListableBeanFactory.preInstantiateSingletons()建立bean实例 2.缺省采用单例模式 在最近的项目中 ...