Last active
April 12, 2017 01:33
-
-
Save linsea/c83109cfadf0116db654813e2edb5d13 to your computer and use it in GitHub Desktop.
任务运行计时工具
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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