「翻」Callable 和 Future

为什么需要Callable?

有两种创建线程的方法,一种是通过扩展Thread类,另一种是通过使用Runnable创建线程。

但是,Runnable缺少的一项功能是,当线程终止(即run()完成)时,我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。

Callable vs Runnable

  • 实现Runnable需要实现不返回任何内容的run()方法,而对于Callable,需要实现在完成后返回结果的call()方法。请注意,无法使用Callable创建线程,只能使用Runnable创建线程。
    • 为什么不能创建线程涉及到ExecutorService的submit方法
  • 另一个区别是call()方法可以引发异常,而run()则不能。

  • 这是示例Callable的代码,该示例将在大约0 – 4秒的延迟后返回一个随机数。

// 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; 
    } 
} 

Future

当call()方法完成时,答案必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。

该程序以后将如何存储和获取此结果?

为此,可以使用Future对象。 将Future视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦Callable返回)。 因此,Future基本上是主线程可以跟踪进度以及其他线程的结果的一种方式。 要实现此接口,必须重写5种方法,但是由于下面的示例使用了库中的具体实现,因此这里仅列出了重要的方法。

其实Callable和Future做了两件事情

  • Callable与Runnable类似,因为它封装了要在另一个线程上运行的任务
  • Future用于存储从另一个线程获得的结果。

需要重写的方法

  • public boolean cancel (boolean mayInterrup):用于停止任务。 如果尚未启动,它将停止任务。 如果已启动,则仅在mayInterrupt为true时才会中断任务。
  • public Object get() throws InterruptedException,ExecutionException:用于获取任务的结果。 如果任务完成,它将立即返回结果,否则将等待任务完成,然后返回结果。
  • public boolean isDone():如果任务完成,则返回true,否则返回false

要创建线程,需要Runnable接口。 为了获得结果,需要Future类。

Java库有具体的类型FutureTask,该类型实现Runnable和Future,并方便地组合这两种功能。

可以通过为其构造函数提供Callable来创建FutureTask。 然后,将FutureTask对象提供给Thread的构造函数以创建Thread对象。

再次强调,无法直接使用Callable创建线程。

这是使用Callable和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 implements both Runnable and Future 
        FutureTask[] randomNumberTasks = new FutureTask[5];

        for (int i = 0; i < 5; i++) {
            Callable callable = new CallableExample();

            // 用 Callable 创建 FutureTask
            randomNumberTasks[i] = new FutureTask(callable);

            // 在实现Runnable时,使用FutureTask创建线程
            Thread t = new Thread(randomNumberTasks[i]);
            t.start();
        }

        for (int i = 0; i < 5; i++) {
            //  Future, we can call get() 
            System.out.println(randomNumberTasks[i].get());
            // 该方法将阻塞直到获得结果。
            // get方法可以引发检查异常,例如被中断时。 这就是将throws子句添加到main的原因
        }
    }
} 

猜你喜欢

转载自www.cnblogs.com/antonzhao/p/12505356.html
今日推荐