广告位联系
返回顶部
分享到

Java并行执行任务的几种方案介绍

java 来源:互联网 作者:秩名 发布时间:2021-11-05 08:34:00 人浏览
摘要

背景 最近在排查生产环境问题,发现商品详情接口时不时会报RPC调用超时,检查代码发现接口里面查询活动耗时比较长,都是串行执行的,仔细查看发现完全可以改成并行去执行,缩短

背景

最近在排查生产环境问题,发现商品详情接口时不时会报RPC调用超时,检查代码发现接口里面查询活动耗时比较长,都是串行执行的,仔细查看发现完全可以改成并行去执行,缩短接口查询耗时。

比如我们的商品详情接口,需要展示立减、阶梯满减、团购等活动标签。需要查询三次不同的活动信息,再组装活动标签信息。

如果每次查询耗时1s,按照串行的方式去调用,整个接口下来至少需要3s,整个耗时,对于我们来讲是无法接受的。其实在jdk中,给我们提供了几种非常便捷的并行执行任务的方法。

CountDownLatch

ExecutorService.invokeAll()

Fork/Join 分而治之 有点类似MapReduce的影子,这个有兴趣的可以自行去了解

改进方案

代码例子:

    private void assemblyActivityTag(CartItemDTO itemDTO){
        //1.查询立减活动信息,耗时1s         
        //2.查询阶梯满减活动信息,耗时1s        
        //3.查询团购活动信息,耗时1s        
        //4.组装活动标签信息,耗时1s 
        // 串行执行下来整个耗时4s
    }

CountDownLatch

    private void assemblyActivityTag(CartItemDTO itemDTO){
        ExecutorService executorService = Executors.newCachedThreadPool();
        CountDownLatch latch = new CountDownLatch(3);
        executorService.execute(new Runnable() {
            @Override
            public void run() {
            //1.查询立减活动信息
                latch.countDown();
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                //2.查询阶梯满减活动信息
                latch.countDown();
            }
        });
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                //3.查询团购活动信息
                latch.countDown();
            }
        });
        try {
            // 一定记得加上timeout时间,防止阻塞主线程
            latch.await(3000,TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //4.等待所有子任务完成,组装活动标签信息
         
        //5.关闭线程池
        executorService.shutdown();
    } 

ExecutorService.invokeAll() 

private void assemblyActivityTag(CartItemDTO itemDTO) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        List<Callable<String>> tasks = Lists.newArrayList();
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //1.查询立减活动信息
                return null;
            }
        });
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //2.查询阶梯满减活动信息
                return null;
            }
        });
        tasks.add(new Callable<String>() {
            @Override
            public String call() throws Exception {
                //3.查询团购活动信息
                return null;
            }
        });
        try {
            List<Future<String>> futureList = executorService.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS);
            for (Future<String> future : futureList) {
                // 获取线程执行结果
                try {
                    String activityTag = future.get();
                } catch (ExecutionException e) {
                    e.printStackTrace();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //4.组装活动标签信息
        //5.关闭线程池
        executorService.shutdown();
    }
 

注意点和区别

在使用CountDownLatch,尽可能使用线程安全的容器去处理子线程的返回值,避免多线程情况下,出现脏数据。

如果想知道每个子线程的对应的返回值,ExecutorService.invokeAll()方式,是没法区分的,只能依赖返回值的顺序去匹配。

使用上面2种方式时,切记设置超时时间,防止子任务执行时间过长,阻塞主线程任务

线程池用完结束,记得shutdown()

java并行执行任务demo

在一个方法中同时调用多个方法或者服务,并等待所有结果返回

package com.test.demo;
import org.junit.Test;
import java.util.concurrent.CompletableFuture;
public class TestFuture {
    @Test
    public void testA(){
        CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> c());
        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> a());
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> b());
        try {
            //获取并行执行任务结果
            System.out.println(future3.get());
            System.out.println(future1.get());
            System.out.println(future2.get());
        }catch (Exception e){
        }
    }
    public String a(){
        try {
            Thread.sleep(1000);
        }catch (Exception e){
        }
        return "a";
    }
    private String b(){
        try {
            //模拟业务执行时间
            Thread.sleep(2000);
        }catch (Exception e){
        }
        return "b";
    }
    private String c(){
        try {
            //模拟业务执行时间
            Thread.sleep(5000);
        }catch (Exception e){
        }
        return "c";
    }
}
 

测试结果:

从执行结果中可以看到一共耗时5s,如果同步进行执行,耗时应该在8s


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/6844903844355260429
相关文章
  • SpringBoot自定义错误处理逻辑介绍

    SpringBoot自定义错误处理逻辑介绍
    1. 自定义错误页面 将自定义错误页面放在 templates 的 error 文件夹下,SpringBoot 精确匹配错误信息,使用 4xx.html 或者 5xx.html 页面可以打印错误
  • Java实现手写一个线程池的代码

    Java实现手写一个线程池的代码
    线程池技术想必大家都不陌生把,相信在平时的工作中没有少用,而且这也是面试频率非常高的一个知识点,那么大家知道它的实现原理和
  • Java实现断点续传功能的代码

    Java实现断点续传功能的代码
    题目实现:网络资源的断点续传功能。 二、解题思路 获取要下载的资源网址 显示网络资源的大小 上次读取到的字节位置以及未读取的字节
  • 你可知HashMap为什么是线程不安全的
    HashMap 的线程不安全 HashMap 的线程不安全主要体现在下面两个方面 在 jdk 1.7 中,当并发执行扩容操作时会造成环形链和数据丢失的情况 在
  • ArrayList的动态扩容机制的介绍

    ArrayList的动态扩容机制的介绍
    对于 ArrayList 的动态扩容机制想必大家都听说过,之前的文章中也谈到过,不过由于时间久远,早已忘却。 所以利用这篇文章做做笔记,加
  • JVM基础之字节码的增强技术介绍

    JVM基础之字节码的增强技术介绍
    字节码增强技术 在上文中,着重介绍了字节码的结构,这为我们了解字节码增强技术的实现打下了基础。字节码增强技术就是一类对现有字
  • Java中的字节码增强技术

    Java中的字节码增强技术
    1.字节码增强技术 字节码增强技术就是一类对现有字节码进行修改或者动态生成全新字节码文件的技术。 参考地址 2.常见技术 技术分类 类
  • Redis BloomFilter布隆过滤器原理与实现

    Redis BloomFilter布隆过滤器原理与实现
    Bloom Filter 概念 布隆过滤器(英语:Bloom Filter)是1970年由一个叫布隆的小伙子提出的。它实际上是一个很长的二进制向量和一系列随机映射
  • Java C++算法题解leetcode801使序列递增的最小交换次

    Java C++算法题解leetcode801使序列递增的最小交换次
    题目要求 思路:状态机DP 实现一:状态机 Java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Solution { public int minSwap(int[] nums1, int[] nums2) { int n
  • Mybatis结果集映射与生命周期介绍

    Mybatis结果集映射与生命周期介绍
    一、ResultMap结果集映射 1、设计思想 对简单的语句做到零配置,对于复杂一点的语句,只需要描述语句之间的关系就行了 2、resultMap的应用场
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计