Creating threads using Callable and Future

Keywords: Java

In addition to the common ways of creating threads, we can also create threads using Callable and Future. This method is essentially consistent with other ways of creating threads. Only this way of creating threads can return the results of threads.

Traditional runnable interface

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

runnable only provides a run method that returns void and does not throw an exception if the execution fails.

As a result, when the thread created by runnable mode is executed, we can not get the return value, and we can not get the specific failure information.

Moreover, Runnable tasks submitted to the thread pool cannot be canceled, which means that if we want to cancel a task, we can only close the entire thread pool.

To sum up, java quit Callable and Future in JDK1.5.

@FunctionalInterface
public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

From the definition of Callable interface, we can see that it supports generics, and the return value type is the generic parameter passed in. It also supports throwing exceptions.

Here is the definition of the Future interface

public interface Future<V> {

/**
* An attempt to cancel the entire task may fail if the task has already been completed or has been cancelled, or cannot be cancelled for other reasons.  
* The cancel task is successfully retrieved. When the cancel method of the whole task is called, the task has not started yet. If the task is already started, the parameter   
*   mayInterruptIfRunning Determines whether to send an interrupt signal to the thread executing the task.  
*   When this method returns, subsequent isDone calls always return true.  
*   Subsequent isCancelled calls always return true if the method returns true.  
*/
boolean cancel(boolean mayInterruptIfRunning);

/**
 * Returns {@code true} if this task was cancelled before it completed
 * normally.
 *
 * @return {@code true} if this task was cancelled before it completed
 */
boolean isCancelled();

/**
 * Returns {@code true} if this task completed.
 *
 * Completion may be due to normal termination, an exception, or
 * cancellation -- in all of these cases, this method will return
 * {@code true}.
 *
 * @return {@code true} if this task completed
 */
boolean isDone();

/**
 * Waits if necessary for the computation to complete, and then
 * retrieves its result.
 *
 * @return the computed result
 * @throws CancellationException if the computation was cancelled
 * @throws ExecutionException if the computation threw an
 * exception
 * @throws InterruptedException if the current thread was interrupted
 * while waiting
 */
V get() throws InterruptedException, ExecutionException;

/**
 * Waits if necessary for at most the given time for the computation
 * to complete, and then retrieves its result, if available.
 *
 * @param timeout the maximum time to wait
 * @param unit the time unit of the timeout argument
 * @return the computed result
 * @throws CancellationException if the computation was cancelled
 * @throws ExecutionException if the computation threw an
 * exception
 * @throws InterruptedException if the current thread was interrupted
 * while waiting
 * @throws TimeoutException if the wait timed out
 */
V get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException;
}

The Future interface provides four methods

boolean cancel(boolean mayInterruptIfRunning);  
boolean isCancelled();  
boolean isDone();  
V get() throws InterruptedException, ExecutionException;  
V get(long timeout, TimeUnit unit)  
 throws InterruptedException, ExecutionException, TimeoutException;

get

The get method is used to get the execution result of Callable. There are usually 5 cases

  1. The task has ended normally. At this time, the Callable return result is obtained.
  2. The task has not finished, which is very likely, because we usually put the task into the thread pool. Maybe you call the get method and the task is still not executed in the task queue. In another case, the task has been executed, but it may take a long time to return,

    In both cases, the result cannot be obtained when the get method is called, which will block the current thread. Know that the task is completed and return the result.

  3. The task is cancelled during the execution of the task. At this time, the task will throw a CancellationException
  4. If the task fails during execution, the task will throw an ExecutionException.
  5. The task timed out. The get method has an overloaded method with parameters. After calling the get method with delay parameter, if the task is completed within the specified time, the result will be returned. If the task cannot complete the work, the TimeoutException will be thrown directly.

isDone

It is used to judge whether the task is completed

Returns true if the task is completed. If the task is not completed, it returns false.

It should be noted that the return of true does not mean that the task has been successfully executed, but only that the task is finished. If the task is canceled during execution. The method still returns true. Because the task is completed, it will not be executed in the future.

Create Future with FutureTask

ExecutorService executorService = Executors.newCachedThreadPool();  
Future<Integer> submit = executorService.submit(new Callable<Integer>() {  
 @Override  
 public Integer call() throws Exception {  
 return null;  
 }  
});

In addition to using the thread pool to submit a Callable task will return a Future object, we can also use FutureTask to get the result of the Future class

Callable<Integer> callable = new Callable<Integer>() {  
 @Override  
 public Integer call() throws Exception {  
 return null;  
 }  
};  
FutureTask<Integer> integerFutureTask = new FutureTask<>(callable);  
new Thread(integerFutureTask).start();

The typical usage is to take the Callable instance as the parameter of FutureTask constructor, generate FutureTask object, and then treat this object as a Runnable object. Here, bridging design pattern is used. Finally, you can get the result of task execution through FutureTask. However, when using Future to get results, it should be noted that the get method will block the caller thread when no task is not completed.

Posted by scrappy1855 on Mon, 29 Jun 2020 23:50:41 -0700