Java計(jì)算代碼段執(zhí)行時(shí)間的詳細(xì)過程
前言
在日常開發(fā)功能時(shí),同一種功能可能會有多種實(shí)現(xiàn)方式。我們需要做一個(gè)取舍。
最常見的條件就是性能、可讀性、可維護(hù)性。
本篇文章,我們主要討論“性能”。
場景
假設(shè)我們現(xiàn)在需要計(jì)算一段代碼的運(yùn)行時(shí)間。
最常見的寫法是,在執(zhí)行這段代碼前,獲得一下當(dāng)前的時(shí)間戳,在執(zhí)行這段代碼后,獲取一下當(dāng)前的時(shí)間戳,然后倆時(shí)間相減,就是花費(fèi)時(shí)間了。
但有時(shí),我們需要將這段代碼執(zhí)行多次。
這種場景是,執(zhí)行的時(shí)間戳很小,沒有可比性。比如執(zhí)行一段代碼,運(yùn)行時(shí)間是 0 或者 2毫秒。
這種時(shí)候你可能會說,那就用一個(gè)for循環(huán),執(zhí)行多次,計(jì)算平均時(shí)間就好了。
問題來了,如果這種相似的操作,寫的多了呢,用的地方很多呢?
我們現(xiàn)在就需要將它給寫成一套模板,只需要簡單的填充參數(shù),調(diào)用,就能實(shí)現(xiàn)上述的功能。
代碼實(shí)現(xiàn)
MethodBody 接口定義
這個(gè)接口主要是用于填充代碼段,因此設(shè)計(jì)為函數(shù)式接口,方便調(diào)用。
package org.feng.calc;
/**
* 運(yùn)行的方法內(nèi)容:使用Lambda
*
* @version V1.0
*/
@FunctionalInterface
public interface MethodBody {
void run();
}
CalcExecuteTimeResult 運(yùn)行結(jié)果實(shí)體
package org.feng.calc;
import lombok.Data;
import java.util.ArrayList;
import java.util.List;
/**
* 計(jì)算執(zhí)行時(shí)間的結(jié)果保存
*
* @version V1.0
*/
@Data
public class CalcExecuteTimeResult {
/**
* 執(zhí)行代碼花費(fèi)的時(shí)間
*/
private List<Long> costTime;
public CalcExecuteTimeResult(int size) {
costTime = new ArrayList<>(size);
}
}
ExecuteTemplate 執(zhí)行模板定義
package org.feng.calc;
import lombok.Getter;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* 執(zhí)行模板
*
* @version V1.0
*/
public class ExecuteTemplate {
private final List<MethodBody> methodBodyList;
@Getter
private CalcExecuteTimeResult calcExecuteTimeResult;
public ExecuteTemplate() {
this.methodBodyList = new ArrayList<>();
}
public void addMethod(MethodBody methodBody) {
methodBodyList.add(methodBody);
}
/**
* 執(zhí)行
*
* @param timeUnit 時(shí)間單位
* @param frequency 頻次-單個(gè)方法{@link MethodBody}實(shí)例執(zhí)行的次數(shù)
*/
void process(TimeUnit timeUnit, long frequency) {
this.calcExecuteTimeResult = new CalcExecuteTimeResult(methodBodyList.size());
List<Long> costTime = calcExecuteTimeResult.getCostTime();
for (MethodBody methodBody : methodBodyList) {
long startTime = getTime(timeUnit);
for (int i = 0; i < frequency; i++) {
methodBody.run();
}
long endTime = getTime(timeUnit);
costTime.add(endTime - startTime);
}
}
private long getTime(TimeUnit timeUnit) {
if (!SUPPORTED_TIME_UNIT.contains(timeUnit)) {
throw new UnsupportedOperationException("不支持的時(shí)間單位:" + timeUnit);
}
if (TimeUnit.NANOSECONDS.equals(timeUnit)) {
return System.nanoTime();
}
return System.currentTimeMillis();
}
/**
* 當(dāng)前支持的時(shí)間單位
*/
private static final Set<TimeUnit> SUPPORTED_TIME_UNIT = Set.of(TimeUnit.MILLISECONDS, TimeUnit.NANOSECONDS);
}
CalcExecuteTimeContext 計(jì)算執(zhí)行時(shí)間上下文
package org.feng.calc;
import lombok.Setter;
import lombok.experimental.Accessors;
import java.util.concurrent.TimeUnit;
/**
* 計(jì)算執(zhí)行時(shí)間-上下文
*
* @version V1.0
*/
@Setter
@Accessors(chain = true)
public class CalcExecuteTimeContext {
private TimeUnit timeUnit;
private Long frequency;
private ExecuteTemplate executeTemplate;
public CalcExecuteTimeResult run() {
executeTemplate.process(timeUnit, frequency);
return executeTemplate.getCalcExecuteTimeResult();
}
public void addMethod(MethodBody methodBody){
executeTemplate.addMethod(methodBody);
}
}
測試運(yùn)行
package org.feng.calc;
import java.util.concurrent.TimeUnit;
/**
* 測試運(yùn)行
*
* @version v1.0
*/
public class Client {
public static void main(String[] args) {
// 初始化上下文:設(shè)置每個(gè)方法執(zhí)行的次數(shù),以及計(jì)算時(shí)間時(shí)使用的時(shí)間單位,執(zhí)行模板
CalcExecuteTimeContext context = new CalcExecuteTimeContext()
.setFrequency(2L)
.setTimeUnit(TimeUnit.MILLISECONDS)
.setExecuteTemplate(new ExecuteTemplate());
context.addMethod(() -> {
System.out.println(111);
System.out.println(111);
System.out.println(111);
System.out.println(111);
System.out.println(111);
});
context.addMethod(() -> {
System.out.println(222);
System.out.println(222);
System.out.println(222);
System.out.println(222);
System.out.println(222);
});
// 計(jì)算得到方法運(yùn)行的結(jié)果
CalcExecuteTimeResult executeTimeResult = context.run();
System.out.println(executeTimeResult);
}
}
運(yùn)行結(jié)果:
111
111
111
111
111
111
111
111
111
111
222
222
222
222
222
222
222
222
222
222
CalcExecuteTimeResult(costTime=[0, 1])
到此這篇關(guān)于Java計(jì)算代碼段執(zhí)行時(shí)間的詳細(xì)過程的文章就介紹到這了,更多相關(guān)Java代碼段執(zhí)行時(shí)間內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
從Android源碼剖析Intent查詢匹配的實(shí)現(xiàn)
這篇文章主要介紹了從Android源碼剖析Intent查詢匹配的實(shí)現(xiàn),Intent部分的源碼為Java代碼,需要的朋友可以參考下2015-07-07
PowerJob的DispatchStrategy方法工作流程源碼解讀
這篇文章主要為大家介紹了PowerJob的DispatchStrategy方法工作流程源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2024-01-01
Java 線程池ExecutorService詳解及實(shí)例代碼
這篇文章主要介紹了Java 線程池ExecutorService詳解及實(shí)例代碼的相關(guān)資料,線程池減少在創(chuàng)建和銷毀線程上所花的時(shí)間以及系統(tǒng)資源的開銷.如果不使用線程池,有可能造成系統(tǒng)創(chuàng)建大量線程而導(dǎo)致消耗系統(tǒng)內(nèi)存以及”過度切換“2016-11-11
淺談Java中OutOfMemoryError問題產(chǎn)生原因
本文主要介紹了淺談Java中OutOfMemoryError問題產(chǎn)生原因,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2023-06-06
SpringBoot集成Caffeine緩存的實(shí)現(xiàn)步驟
Caffeine cache是一個(gè)針對Java的高性能緩存庫。在本文中,我們將介紹它與Spring Boot如何一起使用。2021-05-05

