我正在阅读Elliotte撰写的Java网络编程,在“线程”一章中,他给出了这段代码,作为可以在不同线程中运行的计算的示例。
import java.io.*; import java.security.*; public class ReturnDigest extends Thread { private String filename; private byte[] digest; public ReturnDigest(String filename) { this.filename = filename; } @Override public 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 file din.close(); digest = sha.digest(); } catch (IOException ex) { System.err.println(ex); } catch (NoSuchAlgorithmException ex) { System.err.println(ex); } } public byte[] getDigest() { return digest; } }
为了使用此线程,他给出了一种方法,他称之为新手可能使用的解决方案。
多数新手采用的解决方案是使getter方法返回标志值(或引发异常),直到设置了结果字段为止。
他指的解决方案是:
public static void main(String[] args) { ReturnDigest[] digests = new ReturnDigest[args.length]; for (int i = 0; i < args.length; i++) { // Calculate the digest digests[i] = new ReturnDigest(args[i]); digests[i].start(); } for (int i = 0; i < args.length; i++) { while (true) { // Now print the result 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; } } } }
然后,他继续提出使用回调的更好方法,他将其描述为:
实际上,有一种更简单,更有效的方法来处理问题。可以消除重复轮询每个ReturnDigest对象以查看其是否完成的无限循环。诀窍在于,不是让主程序反复询问每个ReturnDigest线程是否已完成(就像一个五岁的男孩在长途旅行中反复询问“我们到了吗?”,并且几乎令人讨厌),而是让线程告诉主程序何时完成。它是通过在启动它的主类中调用一个方法来实现的。这称为回调,因为线程完成后会回调其创建者
他提供的回调方法的代码如下:
import java.io.*; import java.security.*; public class CallbackDigest implements Runnable { private String filename; public CallbackDigest(String filename) { this.filename = filename; } @Override public 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 file din.close(); byte[] digest = sha.digest(); CallbackDigestUserInterface.receiveDigest(digest, filename); // this is the callback } catch (IOException ex) { System.err.println(ex); } catch (NoSuchAlgorithmException ex) { System.err.println(ex); } } }
的实现CallbackDigestUserInterface
及其用法为:
public class CallbackDigestUserInterface { public static void receiveDigest(byte[] digest, String name) { StringBuilder result = new StringBuilder(name); result.append(": "); result.append(DatatypeConverter.printHexBinary(digest)); System.out.println(result); } public static void main(String[] args) { for (String filename: args) { // Calculate the digest CallbackDigest cb = new CallbackDigest(filename); Thread t = new Thread(cb); t.start(); } } }
但是我的问题(或澄清)是关于他对这种方法的看法……他提到
诀窍在于,您不必让主程序反复询问每个ReturnDigest线程是否已完成,而是让线程告诉主程序何时完成
查看代码,创建运行单独的计算的线程实际上是继续执行原始程序的线程。好像并没有将结果传递回主线程。看来它变成了主线程!
因此,似乎任务完成后并不会通知主线程(而不是主线程轮询)。只是主线程不在乎结果。它运行到最后并结束。完成后,新线程将只运行另一个计算。
我理解正确吗?
这与调试如何配合?现在该线程是否成为主线程?调试器现在会这样对待吗?
还有另一种方法可以将结果实际传递回主线程吗?
我将不胜感激,可以帮助您更好地理解它:)