Runnable接口没有返回值,并且不能抛出已检查异常,只能捕获。
为什么Runnable设计成不能抛出异常?
如果run方法抛出异常,Thread类来接收(run()的执行者是Thread类)。Thread类包括线程池以及能够执行run方法的类,大部分情况下不是我们编写。所以就算是在run方法上抛出异常,处理也不是我们编写。能处理异常的地方就是run方法中。
@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;
}
使用Future获取Callable任务结果
Future可以视作一个存储器,存储call()这个任务的结果。future.get获取Callable接口返回的结果。如果call()未执行完毕,调用get()的线程会阻塞,直到call任务结束。
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
核心方法get(),主要存在三种情况:
- 任务正常完成,返回结果
- 任务执行过程中,get方法阻塞直到完成
- 抛出异常(执行、中断、任务取消、超时四种)
异常抛出的时机:调用future的get方法。
cancel()方法
- 任务未执行,则任务会被取消,返回true。
- 任务已完成,或者已取消,返回false。
- 任务在执行中,根据参数判断。参数true,发送一个中断信号;false不发送。
cancel方法传入false,对于执行中的任务没有意义,用于避免启动还未启动的线程。
public class FutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<Integer> callable = () -> {
TimeUnit.SECONDS.sleep(3);
return (int) (Math.random() * 10);
};
Future<Integer> future = pool.submit(callable);
System.out.println(future.get());
}
}
使用FutureTask创建Future
FutureTask对Callable任务进行封装,作为任务使用,
public class FutureTaskDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService pool = Executors.newFixedThreadPool(10);
Callable<Integer> callable = () -> {
TimeUnit.SECONDS.sleep(3);
return (int) (Math.random() * 10);
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
pool.submit(futureTask);
System.out.println(futureTask.get());
}
}
Future使用的注意点
Future使用的注意点:
- 生命周期不能回退,一旦结束不能从头再来。
- 使用循环批量获取future时,如果有一部分线程较慢,会阻塞其他线程。可以采用get的timeout限制。
List<Future> futures = new ArrayList<>();
for (int i = 0; i < 20; i++) {
Future<Integer> future = service.submit(new CallableTask());
futures.add(future);
}