問題
一直在使用如下代碼進(jìn)行程序耗時(shí)計(jì)算和性能調(diào)試同仆,但是對其返回值代表的具體意義卻不甚了解。
Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop(); // optional
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"
查看源碼發(fā)現(xiàn)其代碼并不復(fù)雜惫叛,下面就對其源碼進(jìn)行剖析和解釋当凡。
源碼剖析
public final class Stopwatch {
private final Ticker ticker;//計(jì)時(shí)器,用于獲取當(dāng)前時(shí)間
private boolean isRunning;//計(jì)時(shí)器是否運(yùn)行中的狀態(tài)標(biāo)記
private long elapsedNanos;//用于標(biāo)記從計(jì)時(shí)器開啟到調(diào)用統(tǒng)計(jì)的方法時(shí)過去的時(shí)間
private long startTick;//計(jì)時(shí)器開啟的時(shí)刻時(shí)間
}
通過對elapsedNanos如叼、startTick結(jié)合當(dāng)前時(shí)刻時(shí)間冰木,可以計(jì)算出我們所需要的程序運(yùn)行流逝的時(shí)間長度。
首先來看Ticker工具類:
public static Stopwatch createStarted() {
return new Stopwatch().start();
}
Stopwatch() {
this.ticker = Ticker.systemTicker();
}
private static final Ticker SYSTEM_TICKER =
new Ticker() {
@Override
public long read() {
//ticker工具類read方法笼恰,直接獲取機(jī)器的毫秒時(shí)間
return Platform.systemNanoTime();
}
};
static long systemNanoTime() {
return System.nanoTime();
}
StopWatch的幾個(gè)關(guān)鍵方法:
public Stopwatch start() {
checkState(!isRunning, "This stopwatch is already running.");
isRunning = true;
startTick = ticker.read();//設(shè)置startTick時(shí)間為stopwatch開始啟動的時(shí)刻時(shí)間
return this;
}
public Stopwatch stop() {
long tick = ticker.read();
checkState(isRunning, "This stopwatch is already stopped.");
isRunning = false;
//設(shè)置elapsedNanos時(shí)間為方法調(diào)用時(shí)間-stopwatch開啟時(shí)間+上次程序stopwatch的elapsedNanos歷史時(shí)間
elapsedNanos += tick - startTick;
return this;
}
public long elapsed(TimeUnit desiredUnit) {
return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
}
private long elapsedNanos() {
//如果stopwatch仍在運(yùn)行中踊沸,返回當(dāng)前時(shí)刻時(shí)間-stopwatch開啟時(shí)刻時(shí)間+歷史elapsedNanos時(shí)間(elapsedNanos只在stop和reset時(shí)會更新)
//如果stopwatch已停止運(yùn)行,則直接返回elapsedNanos社证,詳見stop()
return isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
}
結(jié)論
調(diào)用方式1:
Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop(); // optional
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"
使用stopwatch對程序運(yùn)行時(shí)間進(jìn)行調(diào)試逼龟,首先調(diào)用StopWatch.createStarted()
創(chuàng)建并啟動一個(gè)stopwatch實(shí)例,調(diào)用stopwatch.stop()停止計(jì)時(shí)追葡,此時(shí)會更新stopwatch的elapsedNanos時(shí)間腺律,為stopwatch開始啟動到結(jié)束計(jì)時(shí)的時(shí)間,再次調(diào)用stopwatch.elapsed()宜肉,獲取stopwatch在start-stop時(shí)間段匀钧,時(shí)間流逝的長度。
調(diào)用方式2:
Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
//stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"
createStarted啟動了一個(gè)stopwatch實(shí)例谬返,stopwatch的時(shí)間持續(xù)流逝之斯,調(diào)用elapsed方法,返回isRunning ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
遣铝,此時(shí)得到的返回值是當(dāng)前時(shí)間和stopwatch.start()時(shí)刻時(shí)間的時(shí)間差值佑刷,所以是一個(gè)持續(xù)遞增的時(shí)間。
如果需要在程序中對關(guān)鍵步驟的每一步進(jìn)行進(jìn)行持續(xù)度量酿炸,需要使用如下調(diào)用方式
Stopwatch stopwatch = Stopwatch.createStarted();
doSomething();
stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"
stopwatch.reset().start();
doSomething();
stopwatch.stop();
long millis = stopwatch.elapsed(MILLISECONDS);
log.info("time: " + stopwatch); // formatted string like "12.3 ms"