Java简单方法实现子任务耗时统计

 更新时间:2026年01月13日 09:08:19   作者:桦说编程  
在并发编程中,我们经常需要将一个大任务拆分成多个子任务并行执行,但随之而来的问题是如何准确统计每个子任务的耗时,下面我们来看看如何使用Java实现吧

背景

在并发编程中,我们经常需要将一个大任务拆分成多个子任务并行执行。但随之而来的问题是:如何准确统计每个子任务的耗时?

传统的做法是在业务代码中手动埋点,但这样会导致代码侵入性强、难以维护。本文介绍一种基于装饰器模式的优雅实现方案。

核心思路

通过包装 Callable 接口,在任务执行前后自动记录时间戳,实现对任务生命周期各阶段的监控:

Timeline: submitTime -> startTime -> endTime
              |            |           |
              +-- 等待时间 --+-- 执行时间 --+
              |                         |
              +------- 总耗时 -----------+

代码实现

1. 定义时间记录字段

public class ScopedCallable<V> implements Callable<V> {

    private static final long NANO_TO_MS = 1_000_000L;

    /** 任务名称 */
    private final String taskName;

    /** 被包装的实际任务 */
    private final Callable<V> delegate;

    /** 任务提交时间 (纳秒) */
    private final long submitTime;

    /** 任务开始执行时间 (纳秒) */
    private long startTime;

    /** 任务执行结束时间 (纳秒) */
    private long endTime;
}

2. 在构造函数中记录提交时间

public ScopedCallable(String taskName, Callable<V> delegate) {
    this.taskName = Objects.requireNonNull(taskName);
    this.delegate = Objects.requireNonNull(delegate);
    this.submitTime = System.nanoTime();  // 记录提交时间
}

3. 在 call() 方法中记录执行时间

@Override
public V call() throws Exception {
    try {
        startTime = System.nanoTime();   // 记录开始时间
        return delegate.call();           // 执行实际任务
    } finally {
        endTime = System.nanoTime();      // 记录结束时间
        reportMetrics();                  // 上报监控指标
    }
}

4. 计算各阶段耗时

/** 执行耗时 = 结束时间 - 开始时间 */
public long executionTime() {
    return endTime - startTime;
}

/** 等待耗时 = 开始时间 - 提交时间 */
public long waitTime() {
    return startTime - submitTime;
}

/** 总耗时 = 结束时间 - 提交时间 */
public long totalTime() {
    return endTime - submitTime;
}

5. 上报监控指标

private void reportMetrics() {
    long execMs = executionTime() / NANO_TO_MS;
    long waitMs = waitTime() / NANO_TO_MS;
    long totalMs = totalTime() / NANO_TO_MS;

    System.out.println("[" + taskName + "] 执行耗时: " + execMs + "ms");
    System.out.println("[" + taskName + "] 等待耗时: " + waitMs + "ms");
    System.out.println("[" + taskName + "] 总耗时: " + totalMs + "ms");
}

设计要点

要点说明
纳秒精度使用 System.nanoTime() 而非 currentTimeMillis(),精度更高且不受系统时钟调整影响
finally 块确保即使任务抛异常也能记录结束时间
透明包装对业务代码无侵入,只需在提交任务时包装一层

使用示例

public static void main(String[] args) throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(2);

    // 提交包装后的任务
    Future<String> future = executor.submit(
        new ScopedCallable<>("queryDB", () -> {
            Thread.sleep(100);  // 模拟耗时操作
            return "result";
        })
    );

    System.out.println("结果: " + future.get());
    executor.shutdown();
}

输出示例:

[queryDB] 执行耗时: 102ms
[queryDB] 等待耗时: 0ms
[queryDB] 总耗时: 102ms
结果: result

总结

通过装饰器模式包装 Callable,可以优雅地实现:

  • 提交时间、等待时间、执行时间 的自动采集
  • 监控指标 的自动上报

这种方案的核心优势是零侵入——业务代码无需修改,只需在任务提交处统一包装即可。

到此这篇关于Java简单方法实现子任务耗时统计的文章就介绍到这了,更多相关Java统计任务耗时内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 一文详解如何指定Maven的JDK版本

    一文详解如何指定Maven的JDK版本

    这篇文章主要介绍了如何修改Maven的可执行文件以指定JDK版本,并验证Maven是否使用了正确的JDK版本,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • MyBatis中XML映射器的实现

    MyBatis中XML映射器的实现

    MyBatis的真正强大在于它的语句映射,映射器的XML文件就显得相对简单,本文主要介绍了MyBatis中XML映射器的实现,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • 关于SpringBoot的热部署方案

    关于SpringBoot的热部署方案

    这篇文章主要介绍了关于SpringBoot的热部署方案,每次修改代码就得将项目重启,重新部署,对于一些大型应用来说,重启时间需要花费大量的时间成本,本文就来详解热部署方案,需要的朋友可以参考下
    2023-05-05
  • springboot如何配置允许跨域访问

    springboot如何配置允许跨域访问

    这篇文章主要介绍了springboot如何配置允许跨域访问,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • java异常继承何类,运行时异常与一般异常的区别(详解)

    java异常继承何类,运行时异常与一般异常的区别(详解)

    下面小编就为大家带来一篇java异常继承何类,运行时异常与一般异常的区别(详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-11-11
  • Java中RedisUtils工具类的使用

    Java中RedisUtils工具类的使用

    本文主要介绍了Java中RedisUtils工具类的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • Spring5新功能日志框架Log4j2整合示例

    Spring5新功能日志框架Log4j2整合示例

    这篇文章主要为大家介绍了Spring5新功能之日志框架Log4j2的整合示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-05-05
  • springboot实现基于aop的切面日志

    springboot实现基于aop的切面日志

    这篇文章主要为大家详细介绍了springboot实现基于aop的切面日志,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-09-09
  • Spring如何使用xml创建bean对象

    Spring如何使用xml创建bean对象

    这篇文章主要介绍了Spring如何使用xml创建bean对象,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Spring中使用copyProperties方法进行对象之间的属性赋值详解

    Spring中使用copyProperties方法进行对象之间的属性赋值详解

    这篇文章主要介绍了Spring中使用copyProperties方法进行对象之间的属性赋值详解,使用org.springframework.beans.BeanUtils.copyProperties方法进行对象之间属性的赋值,避免通过get、set方法一个一个属性的赋值,需要的朋友可以参考下
    2023-12-12

最新评论