Callable 是一个泛型接口,里面只有一个 call() 方法,该方法可以返回泛型值 V.
Callable<String> callable = ()->{
//模拟子线程细节,在此睡眠5s
//由于call方法会抛出Exception,这里的操作不用像使用Runnable的run方法那样try/catch了
Thread.sleep(5000);
return "Hello from Callable";
};
Runnable 和 Callable
执行机制
Runnable既可以用在 Thread 类中,也可以用在 ExecutorService类中配合线程池的使用.
Callable 只能在 ExecutorService 中使用.
异常处理
Runnable 接口中的 run 方法签名上没有 throws,自然也就没办法向上传播受检异常.
Callable 的 call() 方法签名却有 throws,所以它可以处理受检异常.
Future
-
-
boolean
cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。
此方法返回后,后续调用isDone()将始终返回true 。 随后电话isCancelled()总是返回true如果此方法返回true 。
V
get()
等待计算完成,然后检索其结果。
V
get(long timeout, TimeUnit unit)
如果需要等待最多在给定的时间计算完成,然后检索其结果(如果可用)。
boolean
isCancelled()
如果此任务在正常完成之前被取消,则返回
true
。boolean
isDone()
返回
true
如果任务已完成。
-
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newSingleThreadExecutor();
//使用Callable, 可以返回值
Callable<String> callable = ()->{
System.out.println("进入Callable的call方法");
//模拟子线程细节,在此睡眠2s
//由于call方法会抛出Exception,这里的操作不用像使用Runnable的run方法那样try/catch了
Thread.sleep(2000);
return "Hello from Callable";
};
System.out.println("提交Callable到线程池");
Future<String> future = executorService.submit(callable);
System.out.println("主线程继续执行");
System.out.println("主线程等待获取Future结果");
String result = future.get();
System.out.println("主线程获取的Future结果:"+result);
executorService.shutdown();
}
主线程调用 future.get() 方法会阻塞自己,直到子任务完成。我们也可以使用 Future 方法提供的 isDone 方法,它可以用来检查 task 是否已经完成.
FutureTask
FutureTask 实现了 RunnableFuture 接口,而 RunnableFuture 接口又分别实现了 Runnable 和 Future 接口,所以可以推断出 FutureTask 具有这两种接口的特性:
有 Runnable 特性,所以可以用在 ExecutorService 中配合线程池使用
有 Future 特性,所以可以从中获取到执行结果
例:
import java.util.concurrent.*;
public class test6 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
//创建线程1的FutureTask
FutureTask<String> ft1 = new FutureTask<>(new T1Task());
FutureTask<String> ft2 = new FutureTask<>(new T2Task());
executorService.submit(ft1);
executorService.submit(ft2);
System.out.println(ft1.get()+ft2.get());
System.out.println("泡好了");
executorService.shutdown();
}
static class T1Task implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("T1:洗水壶---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T1:烧开水---");
TimeUnit.SECONDS.sleep(15);
return "T1:开水烧好";
}
}
static class T2Task implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("T2:洗茶壶---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T2:洗茶杯---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T2:拿茶叶");
TimeUnit.SECONDS.sleep(2);
return "拿到茶叶了";
}
}
}
上面的程序是主线程等待两个 FutureTask 的执行结果,线程1 烧开水时间更长,线程1希望在水烧开的那一刹那就可以拿到茶叶直接泡茶,怎么半呢?
那只需要在线程 1 的FutureTask 中获取 线程 2 FutureTask 的返回结果就可以了,我们稍稍修改一下程序:
import java.util.concurrent.*;
public class test6 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = Executors.newFixedThreadPool(2);
//创建线程1的FutureTask
FutureTask<String> ft2 = new FutureTask<>(new T2Task());
FutureTask<String> ft1 = new FutureTask<>(new T1Task(ft2));
executorService.submit(ft1);
executorService.submit(ft2);
System.out.println(ft1.get());
executorService.shutdown();
}
static class T1Task implements Callable<String> {
private final FutureTask<String> ft2;
public T1Task(FutureTask<String> ft2){
this.ft2 = ft2;
}
@Override
public String call() throws Exception {
System.out.println("T1:洗水壶---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T1:烧开水---");
TimeUnit.SECONDS.sleep(15);
String r2Result = ft2.get();
System.out.println("T2"+r2Result+", 开始泡茶");
return "泡好了";
}
}
static class T2Task implements Callable<String>{
@Override
public String call() throws Exception {
System.out.println("T2:洗茶壶---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T2:洗茶杯---");
TimeUnit.SECONDS.sleep(1);
System.out.println("T2:拿茶叶---");
TimeUnit.SECONDS.sleep(2);
return "拿到茶叶了";
}
}
}