Callable interface

There are two ways to create threads – one by creating a Thread class, and the other by using Runnable. One feature that Runnable lacks, however, is that we can’t make the thread return results when it terminates (that is, when run () completes). To support this functionality, Java provides a Callable interface.

To implement Runnable, you need to implement a run () method that returns nothing, and for Callable, you need to implement a call () method that returns a result on completion. Note that threads cannot be created using Callable, only Runnable. Another difference is that the call () method can throw an exception, while run () cannot. The Call method must be overridden to implement Callable.

/ Java program to illustrate Callable // to return a random number import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.FutureTask; class CallableExample implements Callable { public Object call() throws Exception { // Create random number generator Random generator = new Random(); Integer randomNumber = generator.nextInt(5); // To simulate a heavy computation, // we delay the thread for some random time Thread.sleep(randomNumber * 1000); return randomNumber; }}Copy the code

The Futrue interface

When the call () method completes, the result must be stored in an object known to the main thread so that the main thread can know the result returned by the thread. To do this, you can use a Future object. Think of the Future as the object that holds the result — it may not hold the result for now, but it will hold it in the Future (once the Callable returns). Thus, the Future is basically a way for the main thread to track progress as well as the results of other threads. There are five methods that must be overridden to implement this interface, but because the examples below use concrete implementations from the library, only the important ones are listed here.

  • Item public Boolean Cancel (Boolean mayInterrupt) : Used to stop a task. If it is not started, it stops the task. If started, the task is interrupted only if mayInterrupt is true.
  • Item public Object GET () throws InterruptedException, ExecutionException: Used to obtain the result of the task. If the task completes, it returns the result immediately, otherwise it waits for the task to complete and then returns the result.
  • Item public Boolean isDone () : Returns true if the task is complete, false otherwise

You can see that Callable and Future do two things -Callable is similar to Runnable in that it encapsulates tasks to be run on another thread, and Future is used to store results from another thread. In fact, future can also be used with Runnable.

To create a thread, you need Runnable. To get results, you need a Future.

The Java library has a concrete FutureTask type that implements Runnable and Future and easily combines the two capabilities together. FutureTask can be created by providing a Callable to its constructor. The FutureTask object is then provided to the Thread constructor to create the Thread object. Therefore, threads are created indirectly using Callable.

1. Complete example using Callable and Future

package com.example.thread.callable; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.concurrent.*; /** * @author: GuanBin * @date: Public class TestCallable implements Callable<Object> {private int taskNum; public TestCallable(int taskNum) { this.taskNum = taskNum; Public static void main(String[] args) throws ExecutionException, InterruptedException {test1(); test2(); } / * * * use Executors. NewFixedThreadPool create a thread pool * @ throws InterruptedException * @ throws ExecutionException * / private Static void test1() throws InterruptedException, ExecutionException {system.out.println ("---- program starts ----"); Date date1 = new Date(); int taskSize=5; ExecutorService pool = Executors.newFixedThreadPool(taskSize); List<Future> list = new ArrayList<Future>(); for (int i = 0; i < taskSize; i++) { Callable c = new TestCallable(i); Future f = pool.submit(c); list.add(f); } // Close the thread pool pool.shutdown(); For (Future f: list) {system.out.println (">>>" + f.et ().toString()); } Date date2 = new Date(); System. The out. Println (" -- -- the end of the program program running time [" + (date2. GetTime () - date1. GetTime ()) + "millisecond 】"); @throws ExecutionException @throws InterruptedException */ private static void test2() Throws ExecutionException, InterruptedException {system.out. println("---- program starts ----"); Date date1 = new Date(); int taskSize=5; FutureTask[] randomNumberTasks = new FutureTask[5]; List<Future> list = new ArrayList<Future>(); for (int i = 0; i < randomNumberTasks.length; i++) { Callable c = new TestCallable(i); RandomNumberTasks [I]= new FutureTask(c); Thread t = new Thread(randomNumberTasks[i]); t.start(); } for (Future f: Println (">>>" + f.et ().toString())) {// Get the return value from the Future object and type System.out.println(">>>" + f.et ().toString()); } Date date2 = new Date(); System. The out. Println (" -- -- the end of the program program running time [" + (date2. GetTime () - date1. GetTime ()) + "millisecond 】"); } /** * call method implementation, mainly used to execute the thread concrete implementation, Throws Exception */ @Override Public Object call() throws Exception {system.out.println (">>>" + TaskNum + "task start "); Date dateTmp1 = new Date(); Thread.sleep(1000); Date dateTmp2 = new Date(); long time = dateTmp2.getTime() - dateTmp1.getTime(); System.out.println(">>>" + taskNum + "task terminated "); Return taskNum + "The task returns the running result, the current task time [" + time +" ms] "; }}Copy the code
- program began to run - > > > 0 task start > > > 1 task start > > > 2 task start > > > 3 task start > > > 4 task start > > > 0 task end > > > 0 return run results, the current task time 】 【 1002 milliseconds > > > 1 task end > > > 2 task terminates >>>4 Task Terminated >>>1 Task returned running result, current task time [1005 ms] >>>2 Task returned running result, current task time [1005 ms] >>>3 Task Terminated >>>3 Task returned running result, current task time [1005 ms] >>>4 The task execution result is returned. The current task duration [1005 ms] ---- The program is complete. The program is run ----, and the program is run [1007 ms]Copy the code

2. A complete example using Callable and FutureTask

// Java program to illustrate Callable and FutureTask 
// for random number generation 
import java.util.Random; 
import java.util.concurrent.Callable; 
import java.util.concurrent.FutureTask; 
  
class CallableExample implements Callable 
{ 
  
  public Object call() throws Exception 
  { 
    Random generator = new Random(); 
    Integer randomNumber = generator.nextInt(5); 
  
    Thread.sleep(randomNumber * 1000); 
  
    return randomNumber; 
  } 
  
} 
  
public class CallableFutureTest 
{ 
  public static void main(String[] args) throws Exception 
  { 
  
    // FutureTask is a concrete class that 
    // implements both Runnable and Future 
    FutureTask[] randomNumberTasks = new FutureTask[5]; 
  
    for (int i = 0; i < 5; i++) 
    { 
      Callable callable = new CallableExample(); 
  
      // Create the FutureTask with Callable 
      randomNumberTasks[i] = new FutureTask(callable); 
  
      // As it implements Runnable, create Thread 
      // with FutureTask 
      Thread t = new Thread(randomNumberTasks[i]); 
      t.start(); 
    } 
  
    for (int i = 0; i < 5; i++) 
    { 
      // As it implements Future, we can call get() 
      System.out.println(randomNumberTasks[i].get()); 
  
      // This method blocks till the result is obtained 
      // The get method can throw checked exceptions 
      // like when it is interrupted. This is the reason 
      // for adding the throws clause to main 
    } 
  } 
} 

Copy the code

Once the thread is started, all interactions with the thread use FutureTask because it implements the Future interface. Therefore, there is no need to store Thread objects. With FutureTask objects, you can also cancel a task, check that it is complete, or try to get a result.

3. Use Runnable to get the implementation of the returned result

// Java program to illustrate Runnable 
// for random number generation 
import java.util.Random; 
import java.util.concurrent.Callable; 
import java.util.concurrent.FutureTask; 
  
class RunnableExample implements Runnable 
{ 
    // Shared object to store result 
    private Object result = null; 
  
    public void run() 
    { 
        Random generator = new Random(); 
        Integer randomNumber = generator.nextInt(5); 
  
        // As run cannot throw any Exception 
        try
        { 
            Thread.sleep(randomNumber * 1000); 
        } 
        catch (InterruptedException e) 
        { 
            e.printStackTrace(); 
        } 
  
        // Store the return value in result when done 
        result = randomNumber; 
  
        // Wake up threads blocked on the get() method 
        synchronized(this) 
        { 
            notifyAll(); 
        } 
    } 
  
    public synchronized Object get() 
          throws InterruptedException 
    { 
        while (result == null) 
            wait(); 
  
        return result; 
    } 
} 
  
// Code is almost same as the previous example with a 
// few changes made to use Runnable instead of Callable 
public class RunnableTest 
{ 
    public static void main(String[] args) throws Exception 
    { 
        RunnableExample[] randomNumberTasks = new RunnableExample[5]; 
  
        for (int i = 0; i < 5; i++) 
        { 
            randomNumberTasks[i] = new RunnableExample(); 
            Thread t = new Thread(randomNumberTasks[i]); 
            t.start(); 
        } 
  
        for (int i = 0; i < 5; i++) 
            System.out.println(randomNumberTasks[i].get()); 
    } 
} 
Copy the code