Fin*_*ber 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;
}
}
Run Code Online (Sandbox Code Playgroud)
为了使用此线程,他给出了一种方法,他称之为新手可能使用的解决方案。
多数新手采用的解决方案是使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;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,他继续提出使用回调的更好方法,他将其描述为:
实际上,有一种更简单,更有效的方法来处理问题。可以消除重复轮询每个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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
的实现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();
}
}
}
Run Code Online (Sandbox Code Playgroud)
但是我的问题(或澄清)是关于他对这种方法的看法……他提到
诀窍在于,您不必让主程序反复询问每个ReturnDigest线程是否已完成,而是让线程告诉主程序何时完成
查看代码,创建运行单独的计算的线程实际上是继续执行原始程序的线程。好像并没有将结果传递回主线程。看来它变成了主线程!
因此,似乎任务完成后并不会通知主线程(而不是主线程轮询)。只是主线程不在乎结果。它运行到最后并结束。完成后,新线程将只运行另一个计算。
我理解正确吗?
这与调试如何配合?现在该线程是否成为主线程?调试器现在会这样对待吗?
还有另一种方法可以将结果实际传递回主线程吗?
我将不胜感激,可以帮助您更好地理解它:)
小智 1
其他线程都不会成为“主线程”。您的主线程是从该方法开始的线程main()。它的工作是启动其他线程......然后它就死了。
此时,您永远不会返回到主线程,但子线程具有回调...这意味着当它们完成时,它们知道将程序流程重定向到哪里。
这就是你的receiveDigest()方法。它的工作是在子线程完成后显示其结果。这个方法是从主线程还是子线程调用的?你怎么认为?
可以将结果传递回主线程。为此,您需要防止主线程终止,因此需要有一个循环来使其无限期地运行,并且为了防止该循环占用处理器任务,需要将其置于睡眠状态,而另一个循环则需要将其置于睡眠状态。线程工作。
您可以在此处阅读 fork 和 join 架构的示例:
https://www.tutorialspoint.com/java_concurrency/concurrency_fork_join.htm
| 归档时间: |
|
| 查看次数: |
61 次 |
| 最近记录: |