线程只能执行Runnable任务,但是Runnable任务无法获得返回值。
Callable任务可以获取返回值,但是无法直接通过new Thread.start()方法运行任务。
因此有了FutrueTask这个类型的任务。既可以直接丢到Thread里面执行,又可以获取返回值。
这三者的关系,网上很多。
下面直接通过new Thread().start()来运行多线程
/**
* Runnable
* Callable
* FutureTask
*/
@Slf4j
public class ThreadTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
new Thread(new Runnable() { // 最基础的新建线程的方式~
@Override
public void run() {
log.info("Runnable运行。。。");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
FutureTask<String> futureTask1 = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
log.info("FutureTask.Callable运行。。。");
Thread.sleep(3000);
return "futureTask.callable";
}
}); // 通过FutureTask+Callable的方式,获取线程运行结果的返回值
new Thread(futureTask1).start();
String rslt1 = futureTask1.get();
log.info("异步等待获取到了futureTask1的返回值: {}", rslt1);
// 因为FutureTask的构造函数,对result入参有final的要求,所以不能直接用String,需要新建一个Wrapper类
ResultWrapper rslt2 = new ResultWrapper(); // 这里赋值null,Runnable里的set方法就会NPE
FutureTask<ResultWrapper> futureTask2 = new FutureTask<>(new Runnable() {
@Override
public void run() {
log.info("FutureTask.Runnable运行。。。");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
rslt2.setResult("futureTask.runnable");
}
}, rslt2); // 通过FutureTask+Runnable+Result的方式,获取线程运行结果的返回值
new Thread(futureTask2).start();
ResultWrapper rslt2_ = futureTask2.get();
log.info("异步等待获取到了futureTask2的返回值: {}", rslt2.getResult());
// 这样看来,通过Runnable+Result来获取返回值的途径,太麻烦了,还是直接用Callable吧!
}
@Getter
@Setter
private static class ResultWrapper {
private String result;
}
}
2022-02-13 13:26:14 [INFO] [Thread-0|cn.line.ThreadTest:17] Runnable运行。。。
2022-02-13 13:26:14 [INFO] [Thread-1|cn.line.ThreadTest:29] FutureTask.Callable运行。。。
2022-02-13 13:26:17 [INFO] [main|cn.line.ThreadTest:36] 异步等待获取到了futureTask1的返回值: futureTask.callable
2022-02-13 13:26:25 [INFO] [Thread-2|cn.line.ThreadTest:43] FutureTask.Runnable运行。。。
2022-02-13 13:26:31 [INFO] [main|cn.line.ThreadTest:55] 异步等待获取到了futureTask2的返回值: futureTask.runnable
代码比较随意。由于FutureTask的ge()方法,是阻塞的,因此后面几个FutureTask任务,从结果上来看,都是同步执行的。假如把获取异步结果的get()方法,都放到main函数的末尾去执行的话,就算是真正的异步、并发的了。