Objective
When a developer transitions from a single-threaded development model to a multithreaded environment, a tricky question is how to return data in a thread, and it is well known that the Run () method and the Start () method do not return any values.
When I study the Java Network programming book, I summarize three common methods: Define the Collector, static method callback, and instance method callback.
Defining the Picker
To return data from a thread, the more intuitive idea is to define a get method in the thread, and then call the Get method after the threads have finished executing, and in fact, you will encounter unexpected results.
Code Listing 1-1 shows the definition of the picker in thread
Package Thread;import Java.io.fileinputstream;import Java.io.ioexception;import java.security.DigestInputStream; Import Java.security.messagedigest;import java.security.nosuchalgorithmexception;/** * Created by Michael Wong on 2015/ 11/21. */public class Returndigest extends Thread {/** target file */private String fileName; /** Message Digest */private byte[] digest; Public Returndigest (String fileName) {this.filename = FileName; /** * Calculates a 256-bit SHA-2 message digest */@Override public void Run () {try {FileInputStream FIS = New FileInputStream (FileName); MessageDigest sha = messagedigest.getinstance ("SHA-256"); Digestinputstream dis = new Digestinputstream (FIS, SHA); while (Dis.read ()! =-1); Read the entire file dis.close (); Digest = Sha.digest (); } catch (IOException ex) {ex.printstacktrace (); } catch (NoSuchAlgorithmException ex) {ex.printstacktrace (); } /** * Get Message digest * @return message digest byte array */public byte[] Getdigest () {return this.digest; }}
Code listing 1-2 shows how to call on the main thread
Package Thread;import javax.xml.bind.datatypeconverter;/** * This solution are not guaranteed to work. On some virtual machines, * The main thread takes all of the time avaiable and leaves not time for actual worker threads. * Created by Michael Wong on 2015/11/21. */public class Returndigestuserinterface {public static void main (string[] args) {if (args.length = = 0) { args = new string[] {"E:/ideaprojects/java/netprogramming/src/thread/returndigest.java", "E:/idea Projects/java/netprogramming/src/thread/returndigestuserinterface.java "}; } returndigest[] Returndigest = new Returndigest[args.length]; for (int i = 0; i < args.length; i++) {Returndigest[i] = new Returndigest (args[i]); Returndigest[i].start (); } for (int i = 0, i < args.length; i++) {while (true) {byte[] digest = returndigest[i] . Getdigest (); if (digest! = null) {StrinGbuilder result = new StringBuilder (args[i]); Result.append (":"). Append (Datatypeconverter.printhexbinary (digest)); SYSTEM.OUT.PRINTLN (result); Break } } } }}
in this way, a while (true) {} loop continuously determines whether the digest is empty, that is, whether the child thread is executed. If you're lucky enough to get the right results, but with less efficiency, it's also possible that the program is suspended, depending on the implementation of the virtual machine. Some virtual machines, the main thread will take up all the time, the real worker thread simply does not have the opportunity to be executed, so This practice is not recommended.
static method Callbacks
In fact, it is easier and more efficient to use callback methods to solve such problems. Instead of constantly judging whether a child thread is executing in the main function, it is better to let the child thread actively notify the main thread when the execution is complete, which is similar to the observer design pattern.
Code Listing 2-1 shows a call to a static callback method when a child thread completes execution
Package Thread;import Java.io.fileinputstream;import Java.io.ioexception;import java.security.DigestInputStream; Import Java.security.messagedigest;import java.security.nosuchalgorithmexception;/** * @description return information from thread static callback method * Created by Administrator on 2015/11/3. */public class Callbackdigest implements Runnable {private String fileName; Public Callbackdigest (String fileName) {this.filename = FileName; /** * Calculates a 256-bit SHA-2 message digest */@Override public void Run () {try {FileInputStream FIS = New FileInputStream (FileName); MessageDigest sha = messagedigest.getinstance ("SHA-256"); Digestinputstream dis = new Digestinputstream (FIS, SHA); while (Dis.read ()! =-1); Read the entire file dis.close (); Byte[] Digest = Sha.digest (); Call the keynote class static callback method Callbackdigestuserinterface.receivedigest (Digest, FileName); } catch (IOException e) {e.printstacktrace (); } catch (NoSuchAlgorithmException e) {e.printstacktrace (); } }}
Code listing 2-2 shows the static callback method for the keynote class
package thread;import javax.xml.bind.datatypeconverter;/** * @description static Method Callback * Created by Administrator on 2015/11/3. */public class Callbackdigestuserinterface {public static void Receivedigest (byte[] Digest, String name) {Stri Ngbuilder result = new StringBuilder (name); Result.append (":"); Result.append (Datatypeconverter.printhexbinary (Digest)); SYSTEM.OUT.PRINTLN (result); public static void Main (string[] args) {if (args.length = = 0) {args = new string[] {"E:/ideaprojec Ts/java/netprogramming/src/thread/callbackdigest.java "," E:/ideaprojects/java/netprogramming/src/thread /callbackdigestuserinterface.java "}; } for (String Filename:args) {callbackdigest cb = new Callbackdigest (fileName); Thread thread = new Thread (CB); Thread.Start (); } }}
The static callback method is defined in Callbackdigestuserinterface, called before the end of the run method of the child thread Calbackdigest, the digest is printed to the console, and the digest is assigned a value by the callback method, as a property of the keynote thread. Again to the keynote thread itself, the instance method callback will demonstrate this practice.
instance method callback
The so-called instance method callback refers to the class that is making the callback (the child thread) holds a reference to the callback object (the main thread), and the main thread passes itself as a parameter to the child thread when invoking the child thread. Through constructors, the main thread can pass parameters to child threads.
Listing 3-1 shows a reference to a callback object that is held in a child thread, invoking a callback method through this reference.
Package Thread;import Java.io.fileinputstream;import Java.io.ioexception;import java.security.DigestInputStream; Import Java.security.messagedigest;import java.security.nosuchalgorithmexception;/** * @description The class that makes the callback holds a reference to the callback object * Created by Administrator on 2015/11/3. */public class Instancecallbackdigest implements Runnable {/** * Map file */private String fileName; /** * Callback Object reference */private instancecallbackdigestuserinterface callbackinstance; Public Instancecallbackdigest (String fileName, Instancecallbackdigestuserinterface callbackinstance) {This.filenam e = FileName; This.callbackinstance = callbackinstance; } @Override public void Run () {try {FileInputStream FIS = new FileInputStream (fileName); MessageDigest sha = messagedigest.getinstance ("SHA-256"); Digestinputstream dis = new Digestinputstream (FIS, SHA); while (Dis.read ()! =-1); Dis.close (); Byte[] DigEST = sha.digest (); Callbackinstance.receivedigest (Digest); } catch (IOException e) {e.printstacktrace (); } catch (NoSuchAlgorithmException e) {e.printstacktrace (); } }}
Code listing 3-2 shows the callback object class
Package Thread;import javax.xml.bind.datatypeconverter;/** * @description instance method callback * Created by Administrator on 2015/11/3. */public class Instancecallbackdigestuserinterface {/** * Map file */private String fileName; /** * Abstract * */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 (); try {t.join (); } catch (Interruptedexception e) {e.printstacktrace (); }} protected void Receivedigest (byte[] digest) {this.digest = digest; public string Getdigest () {string result = FileName + ":"; if (digest = = null) {result + = "Digest Not available"; } else {result + = Datatypeconverter.printhexbinary (digest); } return RESult; public static void Main (string[] args) {if (args.length = = 0) {args = new string[] {"E:/ideaprojec Ts/java/netprogramming/src/thread/instancecallbackdigest.java "," E:/IDEAPROJECTS/JAVA/NETPROGRAMMING/SR C/thread/instancecallbackdigestuserinterface.java "}; } for (String Filename:args) {Instancecallbackdigestuserinterface instance = new Instancecallbackdiges Tuserinterface (FileName); Instance.calculatedigest (); System.out.println (Instance.getdigest ()); } }}
The callback method Receivedigest () simply accepts the computed digest data, and the Calculatedigest () method is the one that actually initiates the child thread. The file name and its own app are passed to the child thread by invoking the constructor of the child thread. After the child thread is started (called the Start method) and the child thread's Join method is invoked, the join joins the specified thread to the current thread, merging two parallel threads into sequential execution. The main thread is added here to the child thread, which is done by giving the child thread the main thread call Calculatedigest () to compute the digest, and assigning it to digest to get digest in the main thread call Getdigest (), if executed in parallel, When the main thread calls Getdigest, the child thread may not have finished executing, and digest will be null.
Summary
The first way: Define the picker, not recommended, whether the result is correct depends on the virtual machine thread scheduling and other related design.
The second way: Static callback method, simple and easy to understand, for the simple print output is effective, for the complex needs of the weak.
The third way: the instance method callback, the recommendation uses, the function is rich, can either pass the parameter to the child thread, also can retrieve the data from the child thread, is so-called reciprocity, comes but does not go to indecent assault also. And the autonomy of how the data is handled is in the main thread hand (the program ape has a strong control desire ~v~).
The author's ability is effective, on the analysis to here, inevitably there are mistakes, but also hope that readers criticize correct.
How Java Threads return data