Consider having such a liftoff class:
/*** Class Liftoff.java Implementation Description: Displays the countdown before launch * *@authorWQL September 21, 2016 PM 1:46:46*/ Public classLiftOffImplementsRunnable { PublicLiftOff () {Taskcount++;//count self-increment } Private intCountdown = 3;//Countdown Numbers Private Static intTaskcount = 0; Private intID =Taskcount; @Override Public voidrun () { while(Countdown >= 0) {System.out.println ("Thread number" + ID + "--Countdown" +countdown); Countdown--; Thread.yield (); } }}
And a launch main thread:
Public class Launch { publicstaticvoid main (string[] args) { new LiftOff (); New Thread (LIFTOFF); T.start (); System.out.println ("Launch!") ); }}
Our intention is to show the countdown first and then show "Launch!" ", the result of the operation is
Launch! Thread number 0-- Countdown 3 Thread number 0-- Countdown 2 thread number 0-- Countdown 1 Thread number 0--Countdown 0
Because the main () function is also a thread, the ability of the program to get the correct results depends on the relative execution speed of the thread, which we cannot control. If you want to make the liftoff thread execute before proceeding with the main thread, it is easy to think of a poll:
/*** Class Liftoff.java Implementation Description: Displays the countdown before launch * *@authorWQL September 21, 2016 PM 1:46:46*/ Public classLiftOffImplementsRunnable { PublicLiftOff () {Taskcount++;//count self-increment } Private intCountdown = 3;//Countdown Numbers Private Static intTaskcount = 0; Private intID =Taskcount; Private BooleanIsover =false; @Override Public voidrun () { while(Countdown >= 0) {System.out.println ("Thread number" + ID + "--Countdown" +countdown); Countdown--; if(Countdown < 0) {Isover=true; } Thread.yield (); } } Public BooleanIsover () {returnIsover; } }
We added the Isover variable, set the Isover to true at the end of the countdown, and we constantly judge the Isover state in the main function, and we can tell if the liftoff thread is finished:
Public classLaunch { Public Static voidMain (string[] args) {LiftOff LiftOff=NewLiftOff (); Thread T=NewThread (LIFTOFF); T.start (); while(true) { if(Liftoff.isover ()) {System.out.println ("Launch!"); Break; } } }}
Execute main (), Output:
Thread number 0-- Countdown 3 Thread number 0-- Countdown 2 thread number 0-- Countdown 1 Thread number 0-- Countdown 0 Launch !
This solution is feasible, it will give the correct results in the correct order, but the query is not only wasteful performance, and may be busy with the main line ride too check the completion of the work, so that the specific work thread is not set aside time, the better way is to use the callback (callback) , when the thread completes, it calls its creator in turn, telling it that the work is over:
Public classLiftOffImplementsRunnable {PrivateLaunch Launch; PublicLiftOff (Launch Launch) {Taskcount++;//count self-increment This. Launch =launch; } Private intCountdown = 3;//Countdown Numbers Private Static intTaskcount = 0; Private intID =Taskcount; @Override Public voidrun () { while(Countdown >= 0) {System.out.println ("Thread number" + ID + "--Countdown" +countdown); Countdown--; if(Countdown < 0) {launch.callback (); } Thread.yield (); } }}
Main thread Code:
Public class Launch { publicvoid callBack () { System.out.println ("Launch!") ); } Public Static void Main (string[] args) { new Launch (); New LiftOff (launch); New Thread (LIFTOFF); T.start (); }}
Operation Result:
Thread number 0-- Countdown 3 Thread number 0-- Countdown 2 thread number 0-- Countdown 1 Thread number 0-- Countdown 0 Launch !
The first advantage of the callback mechanism, compared to the polling mechanism, is that it does not waste so much CPU performance, but the more important advantage is that the callback is more flexible and can handle more complex situations involving more threads, objects, and classes.
For example, if more than one object is interested in the calculation of a thread, the thread can hold a list of objects to be recalled, and the objects interested in the results can be registered by calling the method to add themselves to the object list. When the thread finishes processing, the thread will call back those objects that are interested in the results of the calculation. We can define a new interface, all of which will implement this new interface, and the new interface declares the callback method. This mechanism has a more general name: The Observer (Observer) design pattern.
callable
JAVA5 introduces a new approach to multithreaded programming that makes it easier to handle callbacks. The task can implement the callable interface instead of the Runnable interface, submit the task through executor and get a future, and then request the result of the task to the next:
Public classLiftOffImplementsCallable<string> { PublicLiftOff () {Taskcount++;//count self-increment } Private intCountdown = 3;//Countdown Numbers Private Static intTaskcount = 0; Private intID =Taskcount; @Override PublicString Call ()throwsException { while(Countdown >= 0) {System.out.println ("Thread number" + ID + "--Countdown" +countdown); Countdown--; } return"Thread number" + ID + "--end"; }}
Main function:
Public classLaunch { Public Static voidMain (string[] args) {Executorservice executor=Executors.newcachedthreadpool (); Future<String> future = Executor.submit (NewLiftOff ()); Try{String s=Future.get (); System.out.println (s); } Catch(Interruptedexception |executionexception e) {E.printstacktrace (); } System.out.println (Launch "); }}
Operation Result:
Thread number 0-- Countdown 3 Thread number 0-- Countdown 2 thread number 0-- Countdown 1 Thread number 0-- Countdown 0 thread number 0-- End launch!
Easy to submit multiple tasks with executor:
Public classLaunch { Public Static voidMain (string[] args) {Executorservice executor=Executors.newcachedthreadpool (); List<Future<String>> results =NewArraylist<>(); //multi-threaded execution of three tasks for(inti = 0; I < 3; i++) { future<String> future = Executor.submit (NewLiftOff ()); Results.add (future); } //Get threading Results for(future<string>result:results) { Try{String s=Result.get (); System.out.println (s); } Catch(Interruptedexception |executionexception e) {E.printstacktrace (); } } //continue the main thread processSYSTEM.OUT.PRINTLN ("Launch! "); }}
Results:
Thread number 0-- Countdown 3 Thread number 0-- Countdown 2 thread number 0-- Countdown 1 Thread number 0-- Countdown 0 Thread number 2-- Countdown 3 Thread number 2-- Countdown 2 Thread number 1-- Countdown 3 Thread number 1-- Countdown 2 Thread number 1-- Countdown 1 Thread number 1-- Countdown 0 Thread number 2-- Countdown 1 Thread Number 2-- Countdown 0 thread number 0-- End Thread Number 1-- End Thread number 2-- End launch!
As you can see, the Get () method of the future, if the result of the thread is ready, will get the result immediately, and if it is not ready, the polling thread will block until the result is ready.
Benefits
Using callable, we can create many different threads and get the answers we want in the order we need them. In addition, if there is a time-consuming calculation problem, we can also divide the problem into multiple threads to process, and finally summarize the processing results of each thread and analyze it, thus saving time.
How to return information from a thread-polling, callback, callable