Callable接口
Callable
接口是Java 5引入的一个泛型接口,位于java.util.concurrent
包中。它与Runnable
接口类似,都是用来表示一个可以异步执行的任务。不同的是,Callable
可以返回一个结果,并且能够抛出异常。
public interface Callable<V> {
V call() throws Exception;
}
Callable
接口只有一个call()
方法,该方法返回一个泛型类型V
的结果,并且可以抛出Exception
异常。
Callable与Runnable
Callable
和Runnable
接口都可以用来创建线程任务。Runnable接口中只有一个run()方法
public interface Runnable {
public abstract void run();
}
看源码可知实现Runnable接口的线程方法没有返回值,也不能抛出异常。而实现Callable接口的线程方法可以返回一个泛型类型V
的结果,并且可以抛出异常。
使用场景:
Runnable
通常用于不需要返回结果的场景,比如简单的异步任务。Callable
则用于需要返回结果或需要处理异常的场景。
Future接口
Callable
接口通常与Future
接口一起使用。Future
表示一个异步计算的结果,它提供了检查计算是否完成的方法,以及获取计算结果的方法。
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;
}
在Future接口中声明了5个方法,下面依次解释每个方法的作用:
- cancel方法用来取消任务,如果取消任务成功则返回true,如果取消任务失败则返回false。参数mayInterruptIfRunning表示是否允许取消正在执行却没有执行完毕的任务,如果设置true,则表示可以取消正在执行过程中的任务。如果任务已经完成,则无论mayInterruptIfRunning为true还是false,此方法肯定返回false,即如果取消已经完成的任务会返回false;如果任务正在执行,若mayInterruptIfRunning设置为true,则返回true,若mayInterruptIfRunning设置为false,则返回false;如果任务还没有执行,则无论mayInterruptIfRunning为true还是false,肯定返回true。
- isCancelled方法表示任务是否被取消成功,如果在任务正常完成前被取消成功,则返回 true。
- isDone方法表示任务是否已经完成,若任务完成,则返回true;
- get()方法用来获取执行结果,这个方法会产生阻塞,会一直等到任务执行完毕才返回;
- get(long timeout, TimeUnit unit)用来获取执行结果,如果在指定时间内,还没获取到结果,就直接返回null。
FutureTask类
FutureTask 类实现了RunnableFuture<V>接口,先来看一下RunnableFuture接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
RunnableFuture接口继承了Runnable和Future接口,所以它即可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
this.state = NEW;
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result); //将runnable转换成callable
this.state = NEW;
}
事实上,FutureTask是Future接口的一个唯一实现类。
使用示例
- 当我们提交一个
Callable
任务给ExecutorService
时,它会返回一个Future
接口的具体实现类(FutureTask)的对象。通过这个对象,我们可以获取Callable
任务的执行结果。
public class test {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
Future<Integer> future = executorService.submit(()->{
System.out.println("执行了");
return 1024;
});
Integer result = future.get();
System.out.println(result);
executorService.shutdown();
}
}
- 先创建任务,再将任务提交到线程池执行
public class test2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
ExecutorService executorService = new ThreadPoolExecutor(
2,
5,
3,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
FutureTask<Integer> integerFutureTask = null;
try {
integerFutureTask = new FutureTask<>(() -> {
return 1024;
});
executorService.submit(integerFutureTask);
System.out.println(integerFutureTask.get());
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
executorService.shutdown();
}
}
}
- 直接使用Thred启动线程任务
public class test3 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
FutureTask<Integer> integerFutureTask = new FutureTask<>(() -> {
System.out.println(Thread.currentThread().getName()+"执行了");
return 1024;
});
new Thread(integerFutureTask).start();
System.out.println(integerFutureTask.get());
}
}
评论区