preface

With the development of services, the system has more and more functions. At this time, many service operations need to be performed asynchronously to improve efficiency. Most of the time, we can use thread pools to implement asynchronous execution requirements, but sometimes the main process needs to wait for other tasks to complete before it can continue, or the main process needs to know the results of other tasks.

Before we talk about Thread merging, let’s look at how Thread waits for other threads.

Join join thread

A join or CountDownLatch can be used when a thread needs to wait for another thread to finish executing before continuing. This is just a join. CountDownLatch was mentioned in the previous article and will not be covered here.

When thread A calls thread B’s join method, thread A blocks until thread B finishes executing.

Here’s a simple example: How multithreading can be used to do everyday tasks like cooking, cooking and boiling water when you get home from work. Here is the specific process:

The main thread needs to wait for the cooking thread and the boiling thread to finish before continuing to eat and drink. Now let’s see how the code works. Okay

public class JoinDemo {

    static class RiceThread extends Thread{
        @Override
        public void run(a) {
            try {
                System.out.println(Thread.currentThread().getName() + "Start cooking.");
                Thread.sleep(10 * 1000);
                System.out.println(Thread.currentThread().getName() + "Dinner's ready.");
            } catch(InterruptedException e) { e.printStackTrace(); }}}static class WaterThread extends Thread{
        @Override
        public void run(a) {
            try {
                System.out.println(Thread.currentThread().getName() + "Start boiling water");
                Thread.sleep(5 * 1000);
                System.out.println(Thread.currentThread().getName() + "The water is ready.");
            } catch(InterruptedException e) { e.printStackTrace(); }}}public static void main(String[] args){
        try {
            System.out.println(Thread.currentThread().getName() + "Come home");
            // Start the cooking thread
            RiceThread riceThread = new RiceThread();
            riceThread.start();
            // Start the boiling thread
            WaterThread waterThread = new WaterThread();
            waterThread.start();
            System.out.println(Thread.currentThread().getName() + "Start cooking.");
            Thread.sleep(3 * 1000);
            System.out.println(Thread.currentThread().getName() + "The dishes are ready for dinner.");
            waterThread.join();
            riceThread.join();
            System.out.println(Thread.currentThread().getName() + "Eat and drink...");
        } catch(InterruptedException e) { e.printStackTrace(); }}}/ / outputMain went home and Thread-0Main start cooking Thread-1Start boiling water Main dish ready, waiting for the meal Thread-1The water is boiling Thread-0The meal is ready.Copy the code

As you can see from the above example, the main Thread can wait for other threads to complete before executing. However, there is a problem that the main Thread does not know if other threads fail to execute because the run method in Thread does not return a value. Is there a way to do it asynchronously and get results? We can solve it with Future.

Future

The Future is an interface that has the following methods

public interface Future<V> {
    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled(a);
    boolean isDone(a);
    V get(a) throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}
Copy the code

The main way to get the results of an asynchronous task is through the get() method, which blocks until the asynchronous task completes.

A Future is just an interface, we can’t use it directly, we need its implementation class to complete, this time we do not have to implement the class, Java gives us a ready-made implementation class -FutureTask.

Let’s look at the FutureTask constructor

public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;       
}
Copy the code

Constructing FutureTask requires passing in a Callable object. What is this Callable?

We all know that a new thread can be implemented by implementing the Runable interface. The Callable interface is similar to the Runable interface and has only one method:

@FunctionalInterface
public interface Callable<V> {
    V call(a) throws Exception;
}
Copy the code

The main difference between this method and Runable, however, is that it has a return value, which is used to retrieve the result of asynchronous execution.

In Java, threads only have Thread classes. How does this Callable start a new Thread? This class implements the RunnableFuture interface. This interface inherits both Runable and Future. Runable can be passed as a parameter to Thread. This associates Callable with Thread. This may sound a little confusing, but let’s rewrite the cooking process in code.

public class FutureDemo {

    static class RiceThread implements Callable<Boolean> {

        @Override
        public Boolean call(a) throws Exception {
            try {
                System.out.println(Thread.currentThread().getName() + "Start cooking.");
                Thread.sleep(10 * 1000);
                // There is a problem with simulated cooking
                return false;
// system.out.println (thread.currentThread ().getName() + "I'm ready ");
// return true;
            } catch (InterruptedException e) {
                System.out.println("Abnormal cooking");
                return false; }}}static class WaterThread implements Callable<Boolean> {
        @Override
        public Boolean call(a) throws Exception {
            try {
                System.out.println(Thread.currentThread().getName() + "Start boiling water");
                Thread.sleep(5 * 1000);
                System.out.println(Thread.currentThread().getName() + "The water is ready.");
                return true;
            } catch (InterruptedException e) {
                System.out.println("Abnormal boiling water");
                return false; }}}public static void main(String[] args) {
        try {
            Callable<Boolean> riceThread = new RiceThread();
            FutureTask<Boolean> rickTask = new FutureTask<>(riceThread);
            Thread rThread = new Thread(rickTask);

            Callable<Boolean> waterThread = new WaterThread();
            FutureTask<Boolean> waterTask = new FutureTask<>(waterThread);
            Thread wThread = new Thread(waterTask);
            System.out.println(Thread.currentThread().getName() + "Come home");
            // Start the cooking thread
            rThread.start();
            // Start the boiling thread
            wThread.start();
            System.out.println(Thread.currentThread().getName() + "Start cooking.");
            Thread.sleep(3 * 1000);
            System.out.println(Thread.currentThread().getName() + "The dishes are ready for dinner.");
            Boolean wFlag = waterTask.get();
            if(! wFlag) { System.out.println(Thread.currentThread().getName() +"I'm having trouble boiling water. I'm out of water.");
                return;
            }
            Boolean rFlag = rickTask.get();
            if(! rFlag) { System.out.println(Thread.currentThread().getName() +"There's a cooking problem. There's no food.");
                return;
            }
            System.out.println(Thread.currentThread().getName() + "Eat and drink...");
        } catch(Exception e) { e.printStackTrace(); }}}/ / outputMain goes home. Main starts cooking. Thread-0Start cooking Thread-1Start boiling water Main dish ready, waiting for the meal Thread-1There is something wrong with the rice. There is no rice to eatCopy the code

The main thread FutrueTask get() method to get the data, and then carry out the corresponding logic.

conclusion

In Java, threads wait for other threads to finish executing, which can be implemented using joins. Threads wait on other threads and need to get results, which can be done using FutureTask. But both join() and Get () methods in FutureTask block, so are there any methods that can do this without blocking? More on that next time!