千家信息网

Java并行执行任务的方案有哪些

发表于:2025-02-19 作者:千家信息网编辑
千家信息网最后更新 2025年02月19日,本篇内容介绍了"Java并行执行任务的方案有哪些"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!背景最
千家信息网最后更新 2025年02月19日Java并行执行任务的方案有哪些

本篇内容介绍了"Java并行执行任务的方案有哪些"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

背景

最近在排查生产环境问题,发现商品详情接口时不时会报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> tasks = Lists.newArrayList();        tasks.add(new Callable() {            @Override            public String call() throws Exception {                //1.查询立减活动信息                return null;            }        });        tasks.add(new Callable() {            @Override            public String call() throws Exception {                //2.查询阶梯满减活动信息                return null;            }        });        tasks.add(new Callable() {            @Override            public String call() throws Exception {                //3.查询团购活动信息                return null;            }        });        try {            List> futureList = executorService.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS);            for (Future 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 future3 = CompletableFuture.supplyAsync(() -> c());        CompletableFuture future1 = CompletableFuture.supplyAsync(() -> a());        CompletableFuture 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

"Java并行执行任务的方案有哪些"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

0