1. 程式人生 > 程式設計 >Spring計時器StopWatch使用示例

Spring計時器StopWatch使用示例

StopWatch是位於org.springframework.util包下的一個工具類,通過它可方便的對程式部分程式碼進行計時(ms級別),適用於同步單執行緒程式碼塊。

正常情況下,我們如果需要看某段程式碼的執行耗時,會通過如下的方式進行檢視:

public static void main(String[] args) throws InterruptedException {
   StopWatchTest.test0();
//    StopWatchTest.test1();
}

public static void test0() throws InterruptedException {
   long start = System.currentTimeMillis();
   // do something
   Thread.sleep(100);
  long end = System.currentTimeMillis();
  long start2 = System.currentTimeMillis();
  // do something
  Thread.sleep(200);
  long end2 = System.currentTimeMillis();
  System.out.println("某某1執行耗時:" + (end - start));
  System.out.println("某某2執行耗時:" + (end2 - start2));
}

執行結果:
某某1執行耗時:105
某某2執行耗時:203

該種方法通過獲取執行完成時間與執行開始時間的差值得到程式的執行時間,簡單直接有效,但想必寫多了也是比較煩人的,尤其是碰到不可描述的程式碼時,會更加的讓人忍不住多寫幾個bug聊表敬意,而且該結果也不夠直觀,此時會想是否有一個工具類,提供了這些方法,或者自己寫個工具類,剛好可以滿足這種場景,並且把結果更加直觀的展現出來。
首先我們的需求如下:

  1. 記錄開始時間點
  2. 記錄結束時間點
  3. 輸出執行時間及各個時間段的佔比

根據該需求,我們可直接使用org.springframework.util包下的一個工具類StopWatch,通過該工具類,我們對上述程式碼做如下改造:

public static void main(String[] args) throws InterruptedException {
//    StopWatchTest.test0();
   StopWatchTest.test1();
}

public static void test1() throws InterruptedException {
   StopWatch sw = new StopWatch("test");
   sw.start("task1");
   // do something
  Thread.sleep(100);
  sw.stop();
  sw.start("task2");
  // do something
  Thread.sleep(200);
  sw.stop();
  System.out.println("sw.prettyPrint()~~~~~~~~~~~~~~~~~");
  System.out.println(sw.prettyPrint());
}

執行結果:
sw.prettyPrint()~~~~~~~~~~~~~~~~~
StopWatch 'test': running time (millis) = 308
-----------------------------------------
ms % Task name
-----------------------------------------
00104 034% task1
00204 066% task2

start開始記錄,stop停止記錄,然後通過StopWatch的prettyPrint方法,可直觀的輸出程式碼執行耗時,以及執行時間百分比,瞬間感覺比之前的方式高大上了一個檔次。

除此之外,還有以下兩個方法shortSummary,getTotalTimeMillis,檢視程式執行時間。

執行程式碼及結果:

System.out.println("sw.shortSummary()~~~~~~~~~~~~~~~~~");
System.out.println(sw.shortSummary());
System.out.println("sw.getTotalTimeMillis()~~~~~~~~~~~~~~~~~");
System.out.println(sw.getTotalTimeMillis());

執行結果
sw.shortSummary()~~~~~~~~~~~~~~~~~
StopWatch 'test': running time (millis) = 308
sw.getTotalTimeMillis()~~~~~~~~~~~~~~~~~
308

其實以上內容在該工具類中實現也極其簡單,通過start與stop方法分別記錄開始時間與結束時間,其中在記錄結束時間時,會維護一個連結串列型別的tasklist屬性,從而使該類可記錄多個任務,最後的輸出也僅僅是對之前記錄的資訊做了一個統一的歸納輸出,從而使結果更加直觀的展示出來。

StopWatch優缺點:

優點:

  1. spring自帶工具類,可直接使用
  2. 程式碼實現簡單,使用更簡單
  3. 統一歸納,展示每項任務耗時與佔用總時間的百分比,展示結果直觀
  4. 效能消耗相對較小,並且最大程度的保證了start與stop之間的時間記錄的準確性
  5. 可在start時直接指定任務名字,從而更加直觀的顯示記錄結果

缺點:

  1. 一個StopWatch例項一次只能開啟一個task,不能同時start多個task,並且在該task未stop之前不能start一個新的task,必須在該task stop之後才能開啟新的task,若要一次開啟多個,需要new不同的StopWatch例項
  2. 程式碼侵入式使用,需要改動多處程式碼

spring中StopWatch原始碼實現如下:

import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.List;

public class StopWatch {
  private final String id;
  private boolean keepTaskList = true;
  private final List<TaskInfo> taskList = new LinkedList();
  private long startTimeMillis;
  private boolean running;
  private String currentTaskName;
  private StopWatch.TaskInfo lastTaskInfo;
  private int taskCount;
  private long totalTimeMillis;

  public StopWatch() {
    this.id = "";
  }

  public StopWatch(String id) {
    this.id = id;
  }

  public void setKeepTaskList(boolean keepTaskList) {
    this.keepTaskList = keepTaskList;
  }

  public void start() throws IllegalStateException {
    this.start("");
  }

  public void start(String taskName) throws IllegalStateException {
    if (this.running) {
      throw new IllegalStateException("Can't start StopWatch: it's already running");
    } else {
      this.startTimeMillis = System.currentTimeMillis();
      this.running = true;
      this.currentTaskName = taskName;
    }
  }

  public void stop() throws IllegalStateException {
    if (!this.running) {
      throw new IllegalStateException("Can't stop StopWatch: it's not running");
    } else {
      long lastTime = System.currentTimeMillis() - this.startTimeMillis;
      this.totalTimeMillis += lastTime;
      this.lastTaskInfo = new StopWatch.TaskInfo(this.currentTaskName,lastTime);
      if (this.keepTaskList) {
        this.taskList.add(this.lastTaskInfo);
      }

      ++this.taskCount;
      this.running = false;
      this.currentTaskName = null;
    }
  }

  public boolean isRunning() {
    return this.running;
  }

  public long getLastTaskTimeMillis() throws IllegalStateException {
    if (this.lastTaskInfo == null) {
      throw new IllegalStateException("No tasks run: can't get last task interval");
    } else {
      return this.lastTaskInfo.getTimeMillis();
    }
  }

  public String getLastTaskName() throws IllegalStateException {
    if (this.lastTaskInfo == null) {
      throw new IllegalStateException("No tasks run: can't get last task name");
    } else {
      return this.lastTaskInfo.getTaskName();
    }
  }

  public StopWatch.TaskInfo getLastTaskInfo() throws IllegalStateException {
    if (this.lastTaskInfo == null) {
      throw new IllegalStateException("No tasks run: can't get last task info");
    } else {
      return this.lastTaskInfo;
    }
  }

  public long getTotalTimeMillis() {
    return this.totalTimeMillis;
  }

  public double getTotalTimeSeconds() {
    return (double) this.totalTimeMillis / 1000.0D;
  }

  public int getTaskCount() {
    return this.taskCount;
  }

  public StopWatch.TaskInfo[] getTaskInfo() {
    if (!this.keepTaskList) {
      throw new UnsupportedOperationException("Task info is not being kept!");
    } else {
      return (StopWatch.TaskInfo[]) this.taskList.toArray(new StopWatch.TaskInfo[this.taskList.size()]);
    }
  }

  public String shortSummary() {
    return "StopWatch '" + this.id + "': running time (millis) = " + this.getTotalTimeMillis();
  }

  public String prettyPrint() {
    StringBuilder sb = new StringBuilder(this.shortSummary());
    sb.append('\n');
    if (!this.keepTaskList) {
      sb.append("No task info kept");
    } else {
      sb.append("-----------------------------------------\n");
      sb.append("ms   %   Task name\n");
      sb.append("-----------------------------------------\n");
      NumberFormat nf = NumberFormat.getNumberInstance();
      nf.setMinimumIntegerDigits(5);
      nf.setGroupingUsed(false);
      NumberFormat pf = NumberFormat.getPercentInstance();
      pf.setMinimumIntegerDigits(3);
      pf.setGroupingUsed(false);
      StopWatch.TaskInfo[] var7;
      int var6 = (var7 = this.getTaskInfo()).length;

      for (int var5 = 0; var5 < var6; ++var5) {
        StopWatch.TaskInfo task = var7[var5];
        sb.append(nf.format(task.getTimeMillis())).append(" ");
        sb.append(pf.format(task.getTimeSeconds() / this.getTotalTimeSeconds())).append(" ");
        sb.append(task.getTaskName()).append("\n");
      }
    }

    return sb.toString();
  }

  @Override
  public String toString() {
    StringBuilder sb = new StringBuilder(this.shortSummary());
    if (this.keepTaskList) {
      StopWatch.TaskInfo[] var5;
      int var4 = (var5 = this.getTaskInfo()).length;

      for (int var3 = 0; var3 < var4; ++var3) {
        StopWatch.TaskInfo task = var5[var3];
        sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeMillis());
        long percent = Math.round(100.0D * task.getTimeSeconds() / this.getTotalTimeSeconds());
        sb.append(" = ").append(percent).append("%");
      }
    } else {
      sb.append("; no task info kept");
    }

    return sb.toString();
  }

  public static final class TaskInfo {
    private final String taskName;
    private final long timeMillis;

    TaskInfo(String taskName,long timeMillis) {
      this.taskName = taskName;
      this.timeMillis = timeMillis;
    }

    public String getTaskName() {
      return this.taskName;
    }

    public long getTimeMillis() {
      return this.timeMillis;
    }

    public double getTimeSeconds() {
      return (double) this.timeMillis / 1000.0D;
    }
  }

}

到此這篇關於Spring計時器StopWatch使用示例的文章就介紹到這了,更多相關Spring計時器StopWatch內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!