在普通的Web项目开发过程中如果一个接口需要处理的任务比较多响应比较慢,就会很影响体验。我们通常的做法都是会新建一个线程去异步执行耗时的任务,以得到快速的响应。我们来回顾一下Java中创建线程的三种方式。
实现Runable接口之后虽然耗时的任务可以异步执行啦,但是对于有些任务我们难免需要获取它的返回值,这时候重新Runable接口获取返回值就比较复杂啦,但是不要慌我们还可以实现Callable接口重写call方法。但是问题来了我们怎样才能异步的获取call方法中的返回值呢。 如果你经常使用线程池的话会发现ExecutorService.submit()这个方法可以把Callable作为参数传进去,然后返回一个叫做Future的东西。
看到这个方法之后如何获取call方法的返回值的答案就比较明显啦,那就是使用Future。
Future
很明显Future是个接口我们并不能直接使用,但是通过Future的类图我们又可以很快的定位到答案。
没错就是FutureTask.
FutureTask异步获取返回值
通过类图就看见FutureTask和Runable以及Future扯上关系了,和Callable毛关系也没有呀,别急,经常使用Spring框架的同学对于构造参数注入肯定不陌生,我们可以通过构造注入的方式将Callable传进来呀~
由此可见,这个FutureTask确实实现了Runable的特性是个异步的。我们在来康康它获取返回值的特性。
我们想要的返回值也拿到啦。 但是很明显main线程被get方法阻塞了三秒没有立即返回效果又和同步执行区别不大了吗。
使用CompletableFuture
不过不要慌Future还有另外一个更加强大的是实现类CompletableFuture
CompletableFuture强在哪里了呢,强就强在它执行完上面四个静态方法之后可以有个回调方法不会阻塞住主线程。不信你往下看。
自定义一个线程池
代码语言:javascript复制public static ExecutorService customizeThreadPool(){
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>();
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder()
.setNamePrefix("customize-thread-%s").build();
int availableProcessors = Runtime.getRuntime().availableProcessors();
// 计算密集型线程池
int maximumPoolSize = availableProcessors ;
return new ThreadPoolExecutor(availableProcessors-, maximumPoolSize,
, TimeUnit.SECONDS, workQueue,
namedThreadFactory,
new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
throw new RejectedExecutionException("Queue full...");
}
});
}
拿到返回值进行回调
使用CompletableFuture获取其他平台的药品价格
运营的同学有时候难免会观察一下其他平台的商品价钱然后进行一些营销策略的调整,如下就以获取其它平台的药品价格为例展示一下CompletableFuture的强大。
同步
好家伙四个平台40秒呀。
异步
效率直接提升一倍是不是很给力,如果我电脑的cpu在多一核效果将会提升四倍。
我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=1vduboq5oemkv