有关Java中的线程和回调的问题

Finlay Weber 5 java multithreading

我正在阅读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线程是否已完成,而是让线程告诉主程序何时完成

查看代码,创建运行单独的计算的线程实际上是继续执行原始程序的线程。好像并没有将结果传递回主线程。看来它变成了主线程!

因此,似乎任务完成后并不会通知主线程(而不是主线程轮询)。只是主线程不在乎结果。它运行到最后并结束。完成后,新线程将只运行另一个计算。

我理解正确吗?

这与调试如何配合?现在该线程是否成为主线程?调试器现在会这样对待吗?

还有另一种方法可以将结果实际传递回主线程吗?

我将不胜感激,可以帮助您更好地理解它:)