有两种创建线程的方法,一种是通过扩展Thread类,另一种是通过使用Runnable创建线程。
但是,Runnable缺少的一项功能是,当线程终止(即run()完成)时,我们无法使线程返回结果。为了支持此功能,Java中提供了Callable接口。
另一个区别是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;
}
}
当call()方法完成时,答案必须存储在主线程已知的对象中,以便主线程可以知道该线程返回的结果。
该程序以后将如何存储和获取此结果?
为此,可以使用Future对象。 将Future视为保存结果的对象–它可能暂时不保存结果,但将来会保存(一旦Callable返回)。 因此,Future基本上是主线程可以跟踪进度以及其他线程的结果的一种方式。 要实现此接口,必须重写5种方法,但是由于下面的示例使用了库中的具体实现,因此这里仅列出了重要的方法。
其实Callable和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的原因
}
}
}
原文:https://www.cnblogs.com/antonzhao/p/12505356.html