语众不同 發表於 2026-1-13 09:08:19

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

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li>背景</li><li>核心思路</li><li>代码实现</li><ul class="second_class_ul"><li>1. 定义时间记录字段</li><li>2. 在构造函数中记录提交时间</li><li>3. 在 call() 方法中记录执行时间</li><li>4. 计算各阶段耗时</li><li>5. 上报监控指标</li></ul><li>设计要点</li><ul class="second_class_ul"></ul><li>使用示例</li><ul class="second_class_ul"></ul><li>总结</li><ul class="second_class_ul"></ul></ul></div><p class="maodian"></p><h2>背景</h2>
<p>在并发编程中,我们经常需要将一个大任务拆分成多个子任务并行执行。但随之而来的问题是:<strong>如何准确统计每个子任务的耗时?</strong></p>
<p>传统的做法是在业务代码中手动埋点,但这样会导致代码侵入性强、难以维护。本文介绍一种基于装饰器模式的优雅实现方案。</p>
<p class="maodian"></p><h2>核心思路</h2>
<p>通过包装 <code>Callable</code> 接口,在任务执行前后自动记录时间戳,实现对任务生命周期各阶段的监控:</p>
<blockquote><p>Timeline: submitTime -&gt; startTime -&gt; endTime<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; +-- 等待时间 --+-- 执行时间 --+<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |<br />&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; +------- 总耗时 -----------+</p></blockquote>
<p class="maodian"></p><h2>代码实现</h2>
<p class="maodian"></p><h3>1. 定义时间记录字段</h3>
<div class="jb51code"><pre class="brush:java;">public class ScopedCallable&lt;V&gt; implements Callable&lt;V&gt; {

    private static final long NANO_TO_MS = 1_000_000L;

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

    /** 被包装的实际任务 */
    private final Callable&lt;V&gt; delegate;

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

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

    /** 任务执行结束时间 (纳秒) */
    private long endTime;
}
</pre></div>
<p class="maodian"></p><h3>2. 在构造函数中记录提交时间</h3>
<div class="jb51code"><pre class="brush:java;">public ScopedCallable(String taskName, Callable&lt;V&gt; delegate) {
    this.taskName = Objects.requireNonNull(taskName);
    this.delegate = Objects.requireNonNull(delegate);
    this.submitTime = System.nanoTime();// 记录提交时间
}
</pre></div>
<p class="maodian"></p><h3>3. 在 call() 方法中记录执行时间</h3>
<div class="jb51code"><pre class="brush:java;">@Override
public V call() throws Exception {
    try {
      startTime = System.nanoTime();   // 记录开始时间
      return delegate.call();         // 执行实际任务
    } finally {
      endTime = System.nanoTime();      // 记录结束时间
      reportMetrics();                  // 上报监控指标
    }
}
</pre></div>
<p class="maodian"></p><h3>4. 计算各阶段耗时</h3>
<div class="jb51code"><pre class="brush:java;">/** 执行耗时 = 结束时间 - 开始时间 */
public long executionTime() {
    return endTime - startTime;
}

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

/** 总耗时 = 结束时间 - 提交时间 */
public long totalTime() {
    return endTime - submitTime;
}
</pre></div>
<p class="maodian"></p><h3>5. 上报监控指标</h3>
<div class="jb51code"><pre class="brush:java;">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");
}
</pre></div>
<p class="maodian"></p><h2>设计要点</h2>
<table><thead><tr><th>要点</th><th>说明</th></tr></thead><tbody><tr><td>纳秒精度</td><td>使用 System.nanoTime() 而非 currentTimeMillis(),精度更高且不受系统时钟调整影响</td></tr><tr><td>finally 块</td><td>确保即使任务抛异常也能记录结束时间</td></tr><tr><td>透明包装</td><td>对业务代码无侵入,只需在提交任务时包装一层</td></tr></tbody></table>
<p class="maodian"></p><h2>使用示例</h2>
<div class="jb51code"><pre class="brush:java;">public static void main(String[] args) throws Exception {
    ExecutorService executor = Executors.newFixedThreadPool(2);

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

    System.out.println("结果: " + future.get());
    executor.shutdown();
}
</pre></div>
<p>输出示例:</p>
<blockquote><p> 执行耗时: 102ms<br /> 等待耗时: 0ms<br /> 总耗时: 102ms<br />结果: result</p></blockquote>
<p class="maodian"></p><h2>总结</h2>
<p>通过装饰器模式包装 <code>Callable</code>,可以优雅地实现:</p>
<ul><li><strong>提交时间、等待时间、执行时间</strong> 的自动采集</li><li><strong>监控指标</strong> 的自动上报</li></ul>
<p>这种方案的核心优势是<strong>零侵入</strong>&mdash;&mdash;业务代码无需修改,只需在任务提交处统一包装即可。</p>
<p>到此这篇关于Java简单方法实现子任务耗时统计的文章就介绍到这了,更多相关Java统计任务耗时内容请搜索琼殿技术社区以前的文章或继续浏览下面的相关文章希望大家以后多多支持琼殿技术社区!</p>
                           
                            <div class="art_xg">
                              <b>您可能感兴趣的文章:</b><ul><li>Java统计接口耗时的常用方法大全</li><li>Java统计接口耗时的六种常见方法</li><li>Java项目中统计代码耗时的工具类</li><li>Java使用CountDownLatch实现统计任务耗时</li></ul>
                            </div>

                        </div>
                        <!--endmain-->
頁: [1]
查看完整版本: Java简单方法实现子任务耗时统计