前面我们介绍过使用Runnable
接口创建线程,但它有一个缺点,没有提供一个接收返回值的地方。为了实现该功能,JDK5引入了Callable
接口,配合Future
接口能够实现获取子线程返回值的目的。
我们先来看一下这两个接口声明的方法。
Callable.java
package java.util.concurrent;
@FunctionalInterface
public interface Callable<V> {
V call() throws Exception;
}
Callable
接口包含call()
方法,和Runnable
不同的是它具备一个返回值。
Future.java
package java.util.concurrent;
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;
}
前面call()
方法的返回值为了能被主线程读取到,就必须有一个对象来控制和接收返回值,Future
就是为这个目的设计的。cancel()
方法可以停止子线程任务,如果子线程未启动则直接停止,如果子线程已启动则当mayInterruptIfRunning
参数为true
时将其interrupt;isDone()
方法可以获取任务是否完成;get()
方法用于获取任务返回的结果,如果无结果则阻塞等待。
实际上我们没必要直接使用前面的Future
接口,JDK提供了FutureTask
类实现了Future
和Runnable
接口,这里我们介绍其用法。
package com.gacfox.demo;
import java.util.concurrent.Callable;
public class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
Thread.sleep(1000);
return "执行成功";
}
}
package com.gacfox.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Main {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> myThread = new MyThread();
FutureTask<String> futureTask = new FutureTask<>(myThread);
new Thread(futureTask).start();
String s= futureTask.get();
System.out.println(s);
}
}
代码中我们的MyThread
实现了Callable
接口,并返回了一个字符串。main()
方法中,我们创建了一个FutureTask
对象,然后将其传给Thread
类并启动线程,最后我们阻塞等待线程返回值,当线程执行完毕后futureTask.get()
取的返回值,输出后程序结束。