Java中除了Runnable接口,还有Callable接口。
两者区别是,后者可以有返回值,一般用于耗时计算。
Runnable接口在线程中用得比较多,一般可以作为线程执行体,Callable一般会与FutureTask结合使用。
Callable接口的源码如下:
/**
* A task that returns a result and may throw an exception.
* Implementors define a single method with no arguments called
* {@code call}.
* 带有返回值的任务,可能抛出异常。
*
*
The {@code Callable} interface is similar to {@link * java.lang.Runnable}, in that both are designed for classes whose * instances are potentially executed by another thread. A * {@code Runnable}, however, does not return a result and cannot * throw a checked exception. * Callable接口类似于Runnable接口,都是设计用于被其他线程执行的类实例。 * 但是Runnable接口不返回结果,不能抛出一个受检异常。 * *
The {@link Executors} class contains utility methods to * convert from other common forms to {@code Callable} classes. * Executors类包含将其他通用形式转成Callable类的辅助类。 * * @see Executor * @since 1.5 * @author Doug Lea * @param
the result type of method {@code call} */ @FunctionalInterface public interface Callable
{ /** * 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接口用于表示异步计算的结果,该接口包含检查计算是否结束、等待计算结束、获取计算结果的方法。
其中get()可以获取计算结果,在计算完成之前,会一直阻塞当前线程。计算可以被取消。
FutureTask实现了RunnableFuture接口:
public class FutureTask
implements RunnableFuture
{
而RunnableFuture接口继承自Runnable和Future:
public interface RunnableFuture
extends Runnable, Future
{
FutureTask表示可取消的异步计算,作为Future接口的实现。FutureTask可以包装Runnable接口,
另外因为实现了Runnable接口,所以可以提交给Executor执行。
下面用代码测试一下:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class Main {
public static void main(String[] args) throws InterruptedException, ExecutionException {
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(runnable running);
}
};
Callable
callable = new Callable
() { @Override public Integer call() throws Exception { System.out.println(callable running); return 123; } }; Callable
callable1 = new Callable
() { @Override public Integer call() throws Exception { System.out.println(callable1 running); return 123; } }; //runnable Thread thread1 = new Thread(runnable); thread1.start(); //callable FutureTask
future = new FutureTask
(callable); Thread thread2 = new Thread(future); thread2.start(); System.out.println(future is done +future.isDone()); //future.cancel(false); Thread.sleep(1000); System.out.println(future result: +future.get()); ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue
()); executor.execute(runnable); FutureTask
future1 = new FutureTask
(callable1); executor.execute(future1); FutureTask
ft = new FutureTask
(runnable, aaaaa); Thread thread3 = new Thread(ft); thread3.start(); while(!ft.isDone()){ Thread.sleep(1000); } System.out.println(future runnable result: +ft.get()); Future
futureTask = executor.submit(callable); while(!futureTask.isDone()){ Thread.sleep(1000); } System.out.println(futureTask result: +futureTask.get()); exe