当前位置: 首页 > article >正文

串行化执行、并行化执行

文章目录

  • 1、串行化执行
  • 2、并行化测试(多线程环境)
  • 3、任务的执行是异步的,但主程序的继续执行是同步的

可以将多个任务编排为并行和串行化执行。
也可以处理编排的多个任务的异常,也可以返回兜底数据。

1、串行化执行

顺序执行、同步执行
按顺序同步执行
导入 StopWatch 类,这是 Spring 框架提供的一个工具类,用于测量任务的执行时间。

package com.atguigu.structure;

import org.springframework.util.StopWatch;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        StopWatch stopWatch = new StopWatch();

        // 为每个任务分别计时
        stopWatch.start("a任务");
        a();
        stopWatch.stop();

        stopWatch.start("b任务");
        b();
        stopWatch.stop();

        stopWatch.start("c任务");
        c();
        stopWatch.stop();

        // 此时,StopWatch 已经自动停止了总任务的计时(因为最后一个任务也已经停止)
        // 但如果您想显式地停止总任务(尽管在这个例子中它是多余的),您需要确保没有正在运行的任务

        // 打印结果
        System.out.println(stopWatch.prettyPrint());
    }

    public static void a() throws InterruptedException {
        Thread.sleep(3000);
        System.out.println(Thread.currentThread().getName() + " a任务执行完毕-" + System.currentTimeMillis());
    }

    public static void b() throws InterruptedException {
        Thread.sleep(2000);
        System.out.println(Thread.currentThread().getName() + " b任务执行完毕-" + System.currentTimeMillis());
    }

    public static void c() throws InterruptedException {
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + " c任务执行完毕-" + System.currentTimeMillis());
    }
}

由于 a 任务最先执行,它的开始时间是 0 毫秒,结束时间是 3000 毫秒。b 任务在 a 任务结束后立即开始,因此它的开始时间是 3000 毫秒,结束时间是 5000 毫秒。c 任务在 b 任务结束后立即开始,因此它的开始时间是 5000 毫秒,结束时间是 6000 毫秒。

main a任务执行完毕-1727613404687
main b任务执行完毕-1727613406705
main c任务执行完毕-1727613407711
StopWatch '': 6.0325798 seconds
----------------------------------------
Seconds       %       Task name
----------------------------------------
3.0193421     50%     a任务
2.007708      33%     b任务
1.0055297     17%     c任务

2、并行化测试(多线程环境)

多个并发任务
三个任务将并行执行

注意:这里主线程不会等待任务线程完成,因此程序可能会立即退出。
如果需要等待所有任务完成,可以使用CountDownLatch或其他同步机制。

package com.atguigu.structure;

import org.springframework.util.StopWatch;

public class Demo {
    public static void main(String[] args) throws InterruptedException {
        StopWatch stopWatch = new StopWatch();

        // 为每个任务分别计时
        stopWatch.start("a任务");
        new Thread(()->{
            a();
        }).start();
        stopWatch.stop();

        stopWatch.start("b任务");
        new Thread(()->{
            b();
        }).start();
        stopWatch.stop();

        stopWatch.start("c任务");
        new Thread(()->{
            c();
        }).start();
        stopWatch.stop();

        // 打印结果
        System.out.println(stopWatch.prettyPrint());
    }

    public static void a(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " a任务执行完毕-" + System.currentTimeMillis());
    }

    public static void b(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " b任务执行完毕-" + System.currentTimeMillis());
    }

    public static void c(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " c任务执行完毕-" + System.currentTimeMillis());
    }
}
StopWatch '': 0.0022191 seconds
----------------------------------------
Seconds       %       Task name
----------------------------------------
0.0011501     52%     a任务
0.0005202     23%     b任务
0.0005488     25%     c任务

Thread-2 c任务执行完毕-1727615633886
Thread-1 b任务执行完毕-1727615634883
Thread-0 a任务执行完毕-1727615635882

StopWatch 的 start() 和 stop() 方法调用是在主线程中顺序执行的,但是实际的任务(a(), b(), c())是在不同的线程中异步执行的。这会导致 StopWatch 的 stop() 方法在相应的任务线程实际完成之前就被调用了,因此 StopWatch 记录的时间将远小于任务实际执行的时间。

3、任务的执行是异步的,但主程序的继续执行是同步的

使用f1.get(), f2.get(), f3.get()确保主线程等待这些任务完成。

  • 即每个任务都使用了独立的 FutureTask 和线程实例。但是,有一点需要注意:在 main 线程中调用 f1.get(), f2.get(), 和 f3.get() 会阻塞 main 线程,直到相应的 FutureTask 完成。这实际上意味着 main 线程会等待每个任务完成后再继续执行下一个任务,这可能会使得并行执行的优势变得不那么明显,因为任务实际上是顺序执行的(尽管它们在不同的线程中运行)。
  • 因此,从主线程的角度来看,这些任务并不是“真正”的异步执行,因为主线程在等待每个任务完成。然而,从操作系统或 JVM 的角度来看,这些任务确实是在不同的线程中并行执行的(如果系统资源允许的话)。
  • 从全局角度来看,每个任务虽然是异步启动的,但它们依次等待完成,这使得整个程序看起来是按顺序执行的。
  • 主程序通过调用 f1.get(), f2.get(), 和 f3.get() 等待每个任务完成。这意味着主程序会阻塞,直到所有任务都执行完毕。
  • 这种方式确保了任务的执行时间能够被准确地测量,但也意味着主程序不会在所有任务完成之前继续执行其他操作。
  • 由于您还希望使用 StopWatch 来测量每个任务的执行时间,您需要在某个地方等待这些任务完成,所以通过调用 f1.get(), f2.get(), 和 f3.get() 在主线程中阻塞了这些 FutureTask 的执行结果。

总结来说,任务的执行是异步的,但主程序的继续执行是同步的,因为它等待所有异步任务完成。

package com.atguigu.structure;

import org.springframework.util.StopWatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Demo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        StopWatch stopWatch = new StopWatch();

        // 为每个任务分别计时
        stopWatch.start("a任务");
        FutureTask f1 = new FutureTask<>(() -> {
            a();
            return null;
        });
        new Thread(f1).start();
        f1.get();
        stopWatch.stop();

        stopWatch.start("b任务");
        FutureTask f2 = new FutureTask<>(() -> {
            b();
            return null;
        });
        new Thread(f2).start();
        f2.get();
        stopWatch.stop();

        stopWatch.start("c任务");
        FutureTask f3 = new FutureTask<>(() -> {
            c();
            return null;
        });
        new Thread(f3).start();
        f3.get();
        stopWatch.stop();

        // 打印结果
        System.out.println(stopWatch.prettyPrint());
    }

    public static void a(){
        try {
            Thread.sleep(3000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " a任务执行完毕-" + System.currentTimeMillis());
    }

    public static void b(){
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " b任务执行完毕-" + System.currentTimeMillis());
    }

    public static void c(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName() + " c任务执行完毕-" + System.currentTimeMillis());
    }
}
Thread-0 a任务执行完毕-1727619923910
Thread-1 b任务执行完毕-1727619925934
Thread-2 c任务执行完毕-1727619926943
StopWatch '': 6.0475203 seconds
----------------------------------------
Seconds       %       Task name
----------------------------------------
3.0258235     50%     a任务
2.0129727     33%     b任务
1.0087241     17%     c任务

在这里插入图片描述


http://www.kler.cn/news/325374.html

相关文章:

  • 算法记录——树
  • 学生宿舍管理:Spring Boot技术驱动
  • React 中的无限滚动加载数据实现
  • 探索 JUnit 5:下一代 Java 测试框架
  • Android PopupWindow.showAsDropDown报错:BadTokenException: Unable to add window
  • 【设计模式-访问者模式】
  • vue项目报错: At least one is required in a single file component.的主要原因及解决办法
  • MySQL 左右连接
  • Python 统计学
  • 推荐5款ai论文写作常用软件分享!轻松一键生成
  • MongoDB的使用
  • 组合逻辑元件与时序逻辑元件
  • QT开发:深入详解 Qt 核心类:QMap的基本概念和使用方法
  • Android RecyclerView 实现 GridView ,并实现点击效果及方向位置的显示
  • 【测试】——JUnit
  • 全网最全软件测试面试题(含答案解析+文档)
  • Unity 新NavMesh演示(1)
  • 如何在 Ubuntu 22.04 上使用 Browserless?
  • CAD快捷键
  • CMMI认证的好处
  • 在Vue.js中,你可以使用Element UI的el-input组件结合计算属性来实现模糊查询
  • list模拟实现(部分)
  • 统一建模语言(UML)在软件研发过程中常用图接受:类图、用例图、时序图、状态图、活动图、流程图、顺序图
  • 【在Linux世界中追寻伟大的One Piece】命名管道
  • 探索词向量的奥秘:自然语言处理的基石
  • 【SOP】Windows下安装Neo4j流程
  • 头歌 应用密码学实验(1-3实验代码)
  • iOS 项目中的多主题颜色设计与实现
  • python股票因子,交易所服务器宕机,量化交易程序怎么应对
  • docker和ufw冲突问题