Java簡單方法實現(xiàn)子任務(wù)耗時統(tǒng)計
背景
在并發(fā)編程中,我們經(jīng)常需要將一個大任務(wù)拆分成多個子任務(wù)并行執(zhí)行。但隨之而來的問題是:如何準(zhǔn)確統(tǒng)計每個子任務(wù)的耗時?
傳統(tǒng)的做法是在業(yè)務(wù)代碼中手動埋點,但這樣會導(dǎo)致代碼侵入性強、難以維護。本文介紹一種基于裝飾器模式的優(yōu)雅實現(xiàn)方案。
核心思路
通過包裝 Callable 接口,在任務(wù)執(zhí)行前后自動記錄時間戳,實現(xiàn)對任務(wù)生命周期各階段的監(jiān)控:
Timeline: submitTime -> startTime -> endTime
| | |
+-- 等待時間 --+-- 執(zhí)行時間 --+
| |
+------- 總耗時 -----------+
代碼實現(xiàn)
1. 定義時間記錄字段
public class ScopedCallable<V> implements Callable<V> {
private static final long NANO_TO_MS = 1_000_000L;
/** 任務(wù)名稱 */
private final String taskName;
/** 被包裝的實際任務(wù) */
private final Callable<V> delegate;
/** 任務(wù)提交時間 (納秒) */
private final long submitTime;
/** 任務(wù)開始執(zhí)行時間 (納秒) */
private long startTime;
/** 任務(wù)執(zhí)行結(jié)束時間 (納秒) */
private long endTime;
}
2. 在構(gòu)造函數(shù)中記錄提交時間
public ScopedCallable(String taskName, Callable<V> delegate) {
this.taskName = Objects.requireNonNull(taskName);
this.delegate = Objects.requireNonNull(delegate);
this.submitTime = System.nanoTime(); // 記錄提交時間
}
3. 在 call() 方法中記錄執(zhí)行時間
@Override
public V call() throws Exception {
try {
startTime = System.nanoTime(); // 記錄開始時間
return delegate.call(); // 執(zhí)行實際任務(wù)
} finally {
endTime = System.nanoTime(); // 記錄結(jié)束時間
reportMetrics(); // 上報監(jiān)控指標(biāo)
}
}
4. 計算各階段耗時
/** 執(zhí)行耗時 = 結(jié)束時間 - 開始時間 */
public long executionTime() {
return endTime - startTime;
}
/** 等待耗時 = 開始時間 - 提交時間 */
public long waitTime() {
return startTime - submitTime;
}
/** 總耗時 = 結(jié)束時間 - 提交時間 */
public long totalTime() {
return endTime - submitTime;
}
5. 上報監(jiān)控指標(biāo)
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 + "] 執(zhí)行耗時: " + execMs + "ms");
System.out.println("[" + taskName + "] 等待耗時: " + waitMs + "ms");
System.out.println("[" + taskName + "] 總耗時: " + totalMs + "ms");
}
設(shè)計要點
| 要點 | 說明 |
|---|---|
| 納秒精度 | 使用 System.nanoTime() 而非 currentTimeMillis(),精度更高且不受系統(tǒng)時鐘調(diào)整影響 |
| finally 塊 | 確保即使任務(wù)拋異常也能記錄結(jié)束時間 |
| 透明包裝 | 對業(yè)務(wù)代碼無侵入,只需在提交任務(wù)時包裝一層 |
使用示例
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交包裝后的任務(wù)
Future<String> future = executor.submit(
new ScopedCallable<>("queryDB", () -> {
Thread.sleep(100); // 模擬耗時操作
return "result";
})
);
System.out.println("結(jié)果: " + future.get());
executor.shutdown();
}
輸出示例:
[queryDB] 執(zhí)行耗時: 102ms
[queryDB] 等待耗時: 0ms
[queryDB] 總耗時: 102ms
結(jié)果: result
總結(jié)
通過裝飾器模式包裝 Callable,可以優(yōu)雅地實現(xiàn):
- 提交時間、等待時間、執(zhí)行時間 的自動采集
- 監(jiān)控指標(biāo) 的自動上報
這種方案的核心優(yōu)勢是零侵入——業(yè)務(wù)代碼無需修改,只需在任務(wù)提交處統(tǒng)一包裝即可。
到此這篇關(guān)于Java簡單方法實現(xiàn)子任務(wù)耗時統(tǒng)計的文章就介紹到這了,更多相關(guān)Java統(tǒng)計任務(wù)耗時內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring整合WebSocket應(yīng)用示例(上)
以下教程是小編在參與開發(fā)公司的一個crm系統(tǒng),整理些相關(guān)資料,在該系統(tǒng)中有很多消息推送功能,在其中用到了websocket技術(shù)。下面小編整理分享到腳本之家平臺供大家參考2016-04-04
Java 實現(xiàn)repalceAll只替換第二個匹配到的字符串
這篇文章主要介紹了Java 實現(xiàn)repalceAll只替換第二個匹配到的字符串,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-12-12
基于mybatis-plus QueryWrapper 排序的坑
這篇文章主要介紹了mybatis-plus QueryWrapper 排序的坑,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01

