Guava Stopwatch源碼分析

Stopwatch

很多library都有類似Stopwatch的實現,用來計算經過的時間,相當於一個計時器。

package com.google.common.base;

@GwtCompatible(emulated = true)
public final class Stopwatch {
    private final Ticker ticker;
	// 是否運行,start方法將其置爲true
    private boolean isRunning;
    // 花費時間
    private long elapsedNanos;
    // 開始時間
    private long startTick;

    /**
     * 創建Stopwatch但是不啓動
     */
    public static Stopwatch createUnstarted() {
        return new Stopwatch();
    }

    /**
     * 傳入一個tricker創建Stopwatch,不啓動
     */
    public static Stopwatch createUnstarted(Ticker ticker) {
        return new Stopwatch(ticker);
    }

    /**
     * 創建Stopwatch並啓動
     */
    public static Stopwatch createStarted() {
        return new Stopwatch().start();
    }

    /**
     * 傳入一個tricker創建Stopwatch並啓動
     */
    public static Stopwatch createStarted(Ticker ticker) {
        return new Stopwatch(ticker).start();
    }

    // 構造方法
    Stopwatch() {
        // sysTicker返回一個Tiker內部實現類
        this.ticker = Ticker.systemTicker();
    }

    Stopwatch(Ticker ticker) {
        this.ticker = checkNotNull(ticker, "ticker");
    }

    /**
     * 返回isRunning標誌位
     */
    public boolean isRunning() {
        return isRunning;
    }

    /**
     * 開始
     */
    @CanIgnoreReturnValue
    public Stopwatch start() {
        // 不能重複start
        checkState(!isRunning, "This stopwatch is already running.");
        isRunning = true;
        // 返回start時的系統時間
        startTick = ticker.read();
        return this;
    }

    /**
     * 停止
     */
    @CanIgnoreReturnValue
    public Stopwatch stop() {
        // 獲取end時系統時間
        long tick = ticker.read();
        // 不能重複stop
        checkState(isRunning, "This stopwatch is already stopped.");
        isRunning = false;
        // end-start=耗費的時間
        elapsedNanos += tick - startTick;
        return this;
    }

    /**
     * 重置Stopwatch
     */
    @CanIgnoreReturnValue
    public Stopwatch reset() {
        elapsedNanos = 0;
        isRunning = false;
        return this;
    }
	
    /**
     * 如果未stop,返回當前所用時間
     * 如果已stop,返回所用時間
     */
    private long elapsedNanos() {
        return isRunning 
            ? ticker.read() - startTick + elapsedNanos : elapsedNanos;
    }

    /**
   	 * 用指定時間單位返回所用時間,時間四捨五入
   	 */
    public long elapsed(TimeUnit desiredUnit) {
        return desiredUnit.convert(elapsedNanos(), NANOSECONDS);
    }

    /**
     * 返回時間,不丟失精度
     */
    @GwtIncompatible
    @J2ObjCIncompatible
    public Duration elapsed() {
        return Duration.ofNanos(elapsedNanos());
    }

    /** 
     * Returns a string representation of the current elapsed time. 
     */
    @Override
    public String toString() {
        long nanos = elapsedNanos();
		// 選擇合適的時間單位
        TimeUnit unit = chooseUnit(nanos);
        double value = (double) nanos / NANOSECONDS.convert(1, unit);

        // 格式化輸出字符串
        return Platform
            .formatCompact4Digits(value) + " " + abbreviate(unit);
    }
	
    // 根據轉換之後的數值選擇合適的時間單位
    private static TimeUnit chooseUnit(long nanos) {
        if (DAYS.convert(nanos, NANOSECONDS) > 0) {
            return DAYS;
        }
        if (HOURS.convert(nanos, NANOSECONDS) > 0) {
            return HOURS;
        }
        if (MINUTES.convert(nanos, NANOSECONDS) > 0) {
            return MINUTES;
        }
        if (SECONDS.convert(nanos, NANOSECONDS) > 0) {
            return SECONDS;
        }
        if (MILLISECONDS.convert(nanos, NANOSECONDS) > 0) {
            return MILLISECONDS;
        }
        if (MICROSECONDS.convert(nanos, NANOSECONDS) > 0) {
            return MICROSECONDS;
        }
        return NANOSECONDS;
    }

    // 添加單位
    private static String abbreviate(TimeUnit unit) {
        switch (unit) {
            case NANOSECONDS:
                return "ns";
            case MICROSECONDS:
                return "\u03bcs"; // μs
            case MILLISECONDS:
                return "ms";
            case SECONDS:
                return "s";
            case MINUTES:
                return "min";
            case HOURS:
                return "h";
            case DAYS:
                return "d";
            default:
                throw new AssertionError();
        }
    }
}

Tiker。

package com.google.common.base;

@Beta
@GwtCompatible
public abstract class Ticker {
  
    protected Ticker() {}

    /**
     * 返回自此標記器的固定引用點以來經過的納秒數
     */
    @CanIgnoreReturnValue // TODO(kak): Consider removing this
    public abstract long read();

    /**
     * 返回內部實現類實例
     */
    public static Ticker systemTicker() {
        return SYSTEM_TICKER;
    }

    private static final Ticker SYSTEM_TICKER =
        new Ticker() {
            // 返回當前系統時間
        	@Override
            public long read() {
                return Platform.systemNanoTime();
            }
    	};
}

使用

package com.xucc.guava.utilities;

import com.google.common.base.Stopwatch;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

/**
 * @author Created by xuche
 * @date on 2019/7/3
 */
public class StopWatchExample {
	
    private final static Logger LOGGER =
            LoggerFactory.getLogger(StopWatchExample.class);

    public static void main(String[] args) throws InterruptedException {
        processOrder("10");
    }
	
    /**
     * 處理指定訂單號訂單,並打印處理訂單期間所花費的時間
     */
    private static void processOrder(String orderNo) throws InterruptedException {
        LOGGER.info("start process the order [{}].", orderNo);
        Stopwatch stopwatch = Stopwatch.createStarted();
        TimeUnit.SECONDS.sleep(1);

        LOGGER.info("the order [{}] process successful and elapsed [{}].", orderNo, stopwatch.stop());

    }
}

輸出:

2019-07-04 11:16:55.291 [main] INFO  c.x.guava.utilities.StopWatchExample - start process the order [10].
2019-07-04 11:16:55.575 [main] INFO  c.x.guava.utilities.StopWatchExample - the order [10] process successful and elapsed [11.95 μs].
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章