带你认识3个J.U.C组件扩展

时间:2021-11-09 00:39:31
摘要:本文主要为大家讲解3种J.U.C组件扩展。

本文分享自华为云社区《【高并发】J.U.C组件扩展》,作者: 冰 河。

1.FutureTask

FutureTask是J.U.C(java.util.concurrent)下的,但不是AQS(AbstractQueuedSynchronizer)的子类。其对线程结果的处理值得借鉴和在项目中使用。

Thread和Runnable执行完任务无法获取执行结果。Java1.5开始提供了Callable和Future,通过它们可以在任务执行完毕之后,得到任务执行的结果。

Callable与Runnable接口对比

Callable:泛型接口,提供一个call()方法,支持抛出异常,并且执行后有返回值
Runnable:接口,提供一个run()方法,不支持抛出异常,执行后无返回值

Future接口

对于具体的Callable和Runnable任务,可以进行取消,查询任务是否被取消,查询是否完成以及获取结果等。

Future可以监视目标线程调用call()的情况,当调用Future的get()方法时,就可以获得结果。此时,执行任务的线程可能不会直接完成,当前线程就开始阻塞,直到call()方法结束返回结果,当前线程才会继续执行。总之,Future可以得到别的线程任务方法的返回值。

FutureTask类

实现的接口为RunnableFuture,而RunnableFuture接口继承了Runnable和Future两个接口,所以FutureTask类最终也是执行Callable类型的任务。如果FutureTask类的构造方法参数是Runnable的话,会转换成Callable类型。

FutureTask类实现了两个接口:Runnable和Future。所以,它即可以作为Runnable被线程执行,又可以作为Future得到Callable的返回值,这样设计的好处如下:

假设有一个很费时的逻辑,需要计算并且返回这个值,同时,这个值又不是马上需要,则可以使用Runnable和Future的组合,用另外一个线程去计算返回值,而当前线程在使用这个返回值之前,可以做其他的操作,等到需要这个返回值时,再通过Future得到。

Future示例代码如下:

package io.binghe.concurrency.example.aqs;
import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
@Slf4j
public class FutureExample {
 static class MyCallable implements Callable<String>{
 @Override
 public String call() throws Exception {
 log.info("do something in callable");
 Thread.sleep(5000);
 return "Done";
 }
 }
 public static void main(String[] args) throws Exception {
 ExecutorService executorService = Executors.newCachedThreadPool();
 Future<String> future = executorService.submit(new MyCallable());
 log.info("do something in main");
 Thread.sleep(1000);
 String result = future.get();
 log.info("result: {}", result);
 executorService.shutdown();
 }
}