c3 Threads - Returning Infomation From a Thread
来源:互联网 发布:sql virtual table 编辑:程序博客网 时间:2024/06/04 23:23
Returning Info from a Thread
方案一
class DigestThread extends Thread{private String filename;private byte[] digest;public DigestThread(String fileName){this.filename = fileName;}@Overridepublic void run() {try { FileInputStream in = new FileInputStream(filename); MessageDigest sha = MessageDigest.getInstance("SHA-256"); DigestInputStream din = new DigestInputStream(in, sha); while (din.read() != -1) ; din.close(); digest = sha.digest(); } catch (IOException ex) { System.err.println(ex); } catch (NoSuchAlgorithmException ex) { System.err.println(ex); }}public byte[] getDigest(){return digest;}}
public static void main(String[] args) { for (String filename : args) { // Calculate the digest DigestThread dr = new DigestThread(filename); dr.start(); // Now print the result StringBuilder result = new StringBuilder(filename); result.append(": "); byte[] digest = dr.getDigest(); result.append(DatatypeConverter.printHexBinary(digest)); System.out.println(result); } }
输出会报异常“NullPointerException”,因为getDigest()时,digest还未被初始化,也就是那个线程还没有执行完毕。
方案二:
public static void main(String[] args) throws Exception {DigestThread[] digests = new DigestThread[args.length];for(int i=0;i<args.length;i++){digests[i] = new DigestThread(args[i]);digests[i].start();}for(int i=0;i<args.length;i++){StringBuilder result = new StringBuilder(args[i]);result.append(": ");byte[] digest = digests[i].getDigest();result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);}}
如果幸运,会得到想要的结果,但很可能还会得到空指针异常。因为主线程去getDigest时,子线程还未完成。
你能获得的是正常的结果,还是异常还是程序被挂起,依赖于很多因素,包括程序衍生了多少个线程,当前系统的cup和disk的运行速度,系统用了多少cpu,jvm对不同线程分配时间的算法。这叫做“race condition”。
方案三:
public static void main(String[] args) throws Exception {DigestThread[] digests = new DigestThread[args.length];for(int i=0;i<args.length;i++){digests[i] = new DigestThread(args[i]);digests[i].start();}for(int i=0;i<args.length;i++){while(true){byte[] digest = digests[i].getDigest();if(digest != null){StringBuilder result = new StringBuilder(args[i]);result.append(": ");result.append(DatatypeConverter.printHexBinary(digest));System.out.println(result);break;}}}}
菜鸟一般都这么搞,这样做有时也能完成工作,但输出顺序完全按线程启动的顺序,而“忽略、屏蔽”了不同线程间速度的差异,显然,效率上差,做了无用功。但在一些虚拟机上,主线程占用了所有可用时间,而没有时间留给子线程去工作,那在这样的情况下,就不行了。
下面的方案是我应用观察者模式写的:
class DigestTask extends Observable implements Runnable{private String filename;private byte[] digest;public DigestTask(String fileName){this.filename = fileName;}@Overridepublic void run() {try {System.out.println("DigestTask "+filename+"-"+Thread.currentThread().getName()); FileInputStream in = new FileInputStream(filename); MessageDigest sha = MessageDigest.getInstance("SHA-256"); DigestInputStream din = new DigestInputStream(in, sha); while (din.read() != -1) ; din.close(); digest = sha.digest(); this.setChanged(); this.notifyObservers(); } catch (IOException ex) { System.err.println(ex); } catch (NoSuchAlgorithmException ex) { System.err.println(ex); }}public byte[] getDigest(){return digest;}public String getFileName(){return filename;}}
public static void main(String[] args) throws Exception {DigestTask[] digests = new DigestTask[args.length];for(int i=0;i<args.length;i++){digests[i] = new DigestTask(args[i]);digests[i].addObserver(new Observer() {@Overridepublic void update(Observable o, Object arg) {outputDigest(((DigestTask)o).getFileName(), ((DigestTask)o).getDigest());}});Thread t = new Thread(digests[i]);t.start();}}
static void outputDigest(String filename,byte[] digest){StringBuilder result = new StringBuilder(filename);result.append(": ");result.append(DatatypeConverter.printHexBinary(digest));System.out.println("outputDigest "+filename+"-"+Thread.currentThread().getName());System.out.println(result);}
这样只是客户端可以自定义当子线程执行完成后的行为, 本质上还是没有从执行的线程返回数据到主线程。
但接下来作者的解决方案是“CallBack”。“Observer Patern”,一般的callback可以设置一个回调对象,观察者呢可以设置一组,所有对该内容变化感兴趣的callback。
class InstanceCallbackDigest implements Runnable {private String filename;private InstanceCallbackDigestUserInterface callback;public InstanceCallbackDigest(String filename,InstanceCallbackDigestUserInterface callback) {this.filename = filename;this.callback = callback;}@Overridepublic void run() {try {FileInputStream in = new FileInputStream(filename);MessageDigest sha = MessageDigest.getInstance("SHA-256");DigestInputStream din = new DigestInputStream(in, sha);while (din.read() != -1); // read entire filedin.close();byte[] digest = sha.digest();callback.receiveDigest(digest);} catch (Exception ex) {System.err.println(ex);}}}class InstanceCallbackDigestUserInterface {private String filename;private byte[] digest;public InstanceCallbackDigestUserInterface(String filename) {this.filename = filename;}public void calculateDigest() {InstanceCallbackDigest cb = new InstanceCallbackDigest(filename, this);Thread t = new Thread(cb);t.start();}void receiveDigest(byte[] digest) {this.digest = digest;System.out.println(this);}@Overridepublic String toString() {String result = filename + ": ";if (digest != null) {result += DatatypeConverter.printHexBinary(digest);} else {result += "digest not available";}return result;}public static void main(String[] args) {for (String filename : args) {// Calculate the digestInstanceCallbackDigestUserInterface d = new InstanceCallbackDigestUserInterface(filename);d.calculateDigest();}}}
一个单独的类可以当作一个数据结构!
Futures,Callables,Executors
jdk5 提供了方便的使用多线程的方式ExecutorService,接受Callable的实现类,针对每一个Callable都会返回一个Future,通过Future可以获得线程执行的结果,如果线程还未执行完毕,那调用线程会block,直到有结果,如果有结果,那就会立即返回。
假设现在有个任务,在一个数组中找出最大的数,可以用2个线程在做,基本上速度会是单线程的2倍。
class MultithreadedMaxFinder {public static int max(int[] data) throws InterruptedException,ExecutionException {if (data.length == 1) {return data[0];} else if (data.length == 0) {throw new IllegalArgumentException();}// split the job into 2 piecesFindMaxTask task1 = new FindMaxTask(data, 0, data.length / 2);FindMaxTask task2 = new FindMaxTask(data, data.length / 2, data.length);// spawn 2 threadsExecutorService service = Executors.newFixedThreadPool(2);Future<Integer> future1 = service.submit(task1);Future<Integer> future2 = service.submit(task2);return Math.max(future1.get(), future2.get());}}class FindMaxTask implements Callable<Integer> {private int[] data;private int start;private int end;FindMaxTask(int[] data, int start, int end) {this.data = data;this.start = start;this.end = end;}@Overridepublic Integer call() throws Exception {int max = Integer.MIN_VALUE;for (int i = start; i < end; i++) {if (data[i] > max)max = data[i];}return max;}}
注意:调用future1.get()时,如果有结果则立即返回,如果还无结果,则block,等着,直到有结果了,future2.get()也是如此。
0 0
- c3 Threads - Returning Infomation From a Thread
- c3 Threads - Thread Scheduling
- c3 Threads - Thread Pools and Executors
- c3 Threads - Running Threads
- Returning ArrayList from a WebService
- c3 Threads - Synchronization
- c3 Threads - Deadlock
- Returning JSON from a ZF2 controller action
- Returning a Mat from native JNI to Java
- 出现警告:incompatible pointer types returning from a function with result type
- Incompatible pointer types returning 'NSArray *' from a function with result type 'xxx *'
- Returning Objects from Web Services
- Returning Values from Bash Functions
- Returning Values from Bash Functions
- How threads differ from processes
- stackoverflow:Returning an NSString from an NSError
- c3
- c3
- Android开发中如何结束所有的activity
- 荣耀3c四核已经发布
- 码农提高工作效率
- iOS7下UITextView最后一行光标位置问题
- js显示日期和时间
- c3 Threads - Returning Infomation From a Thread
- 练习,体重测试是否超重
- perl常用的内置特殊变量
- 高效程序员的 7 个共同特征
- ios NSString 去除空格和回车
- Mac下Android Studio搭建
- STL 之adjacent_find, merge,inplace_merge
- Making vsftpd with chrooted users work again on Ubuntu 12.04
- 已经笑死9999个了 ,你千万不要做第10000个