Skip to content

Instantly share code, notes, and snippets.

@linsea
Last active April 12, 2017 01:33
Show Gist options
  • Save linsea/c83109cfadf0116db654813e2edb5d13 to your computer and use it in GitHub Desktop.
Save linsea/c83109cfadf0116db654813e2edb5d13 to your computer and use it in GitHub Desktop.
任务运行计时工具
package com.github.linsea.autostopwatch;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
/**
* <p> 任务运行计时工具.
* <p> 此类不会抛出异常, 运行状态不正确时, 会记录下来, 并在最后的toString()方法中打印出来.
* <pre>{@code
* //使用方法:
* ticker.start("taskA"); //开始taskA任务的计时
* doTaskA(); //运行taskA任务
* ticker.stop("taskA"); //结束计时
* ticker.toString(); //查看结果.
* }
* </pre>
*/
public class Ticker {
/** Ticker ID */
private final String id;
private static final long THRESHOLD = 365 * 24 * 60 * 60 * 1000L;
private long tickerStartMillis;
private final Map<String, Pair> taskMap = Collections.synchronizedMap(new LinkedHashMap<String, Pair>());
private final List<String> errorCallSequence = Collections.synchronizedList(new ArrayList<String>()); //error info
public Ticker() {
this("");
}
/**
* 创建一个Ticker, 并且开始计时.
* @param id id
*/
public Ticker(String id) {
this.id = id;
tickerStartMillis = System.currentTimeMillis();
}
public String getId() {
return this.id;
}
/**
* 开始计时名为taskName的任务. 如果taskName的任务之前已经开始, 以首次开始计时为准.
* @param taskName 任务名
*
* @see #stop(String taskName)
*/
public void start(String taskName) {
if(!checkState()) return;
Pair pair = taskMap.get(taskName);
if (pair == null) {
taskMap.put(taskName, new Pair(System.currentTimeMillis(), 0L));
} else { //任务之前已经开始过计时, 以首次开始计时为准
errorCallSequence.add(taskName + " has started, call start again");
}
}
/**
* 停止名为taskName的任务的计时,如果此任务从来没有开始过, 则什么都不做.
* @param taskName 任务名
*
* @see #start(String taskName)
*/
public void stop(String taskName) {
if(!checkState()) return;
long stopTimeMillis = System.currentTimeMillis();
Pair pair = taskMap.get(taskName);
if (pair == null) {
errorCallSequence.add("[" + taskName + "] never started, but call stop");
} else {
if (pair.first > THRESHOLD) { // 正常情况
pair.first = stopTimeMillis - pair.first;
pair.second = stopTimeMillis - tickerStartMillis;
} else {
errorCallSequence.add("[" + taskName + "] has stopped, call stop again");
}
}
}
public String prettyPrint() {
if(!checkState()) return "";
StringBuilder sb = new StringBuilder("Ticker[").append(getId()).append("] :\n");
sb.append("Exec ms | Elapse ms | Task name\n");
synchronized (taskMap) {
Set<Map.Entry<String, Pair>> entries = taskMap.entrySet();
for (Map.Entry<String, Pair> entry : entries) {
String taskName = entry.getKey();
Pair pair = entry.getValue();
if (pair.first > THRESHOLD) {//任务没有call stop,还在运行
long hasRunning = System.currentTimeMillis() - pair.first;
long total = System.currentTimeMillis() - tickerStartMillis;
sb.append(String.format(Locale.getDefault(), "%7d", hasRunning)).append(" | ")
.append(String.format(Locale.getDefault(), "%6d", total)).append(" | ")
.append(taskName).append(" (Running)").append("\n");
} else {
sb.append(String.format(Locale.getDefault(), "%7d",pair.first)).append(" | ")
.append(String.format(Locale.getDefault(), "%6d",pair.second)).append(" | ")
.append(taskName).append("\n");
}
}
}
synchronized (errorCallSequence) {
if (errorCallSequence.size() != 0) {
sb.append("Error task Calls:\n");
for (String s : errorCallSequence) {
sb.append(s).append("\n");
}
}
}
return sb.toString();
}
/**reset之后的Ticker不可再使用*/
public void reset() {
taskMap.clear();
errorCallSequence.clear();
tickerStartMillis = 0;
}
private boolean checkState() {
return tickerStartMillis > 0;
}
/*
public void restart() {
if (tickerStartMillis != 0) {
throw new IllegalStateException("Ticker is running and not call reset()");
} else {
reset();
}
tickerStartMillis = System.currentTimeMillis();
}
*/
@Override
public String toString() {
if (!checkState()) {
return "Ticker(id=" + id + ")";
}
return prettyPrint();
}
private static class Pair {
long first; // 任务未完成时保存任务的开始时间 或者 任务完成时保存任务的执行时间
long second; //任务执行完成时Ticker当前已经走过的时间
Pair(long first, long second) {
this.first = first;
this.second = second;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment