Java计时器StopWatch实现方法代码实例

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

Java计时器StopWatch实现⽅法代码实例下⾯提供三种计时器的写法供⼤家参考,⼤家可以⾃⾏选择⾃⼰钟爱的使⽤。

写法⼀(Spring 包提供的计时器):
import java.text.NumberFormat;
import java.util.LinkedList;
import java.util.List;
/**
* Simple stop watch, allowing for timing of a number of tasks,
* exposing total running time and running time for each named task.
*
* <p>Conceals use of {@code System.currentTimeMillis()}, improving the
* readability of application code and reducing the likelihood of calculation errors.
*
* <p>Note that this object is not designed to be thread-safe and does not
* use synchronization.
*
* <p>This class is normally used to verify performance during proof-of-concepts
* and in development, rather than as part of production applications.
*
* @author Rod Johnson
* @author Juergen Hoeller
* @author Sam Brannen
* @since May 2, 2001
*/
public class StopWatch {
/**
* Identifier of this stop watch.
* Handy when we have output from multiple stop watches
* and need to distinguish between them in log or console output.
*/
private final String id;
private boolean keepTaskList = true;
private final List<TaskInfo> taskList = new LinkedList<TaskInfo>();
/** Start time of the current task */
private long startTimeMillis;
/** Is the stop watch currently running? */
private boolean running;
/** Name of the current task */
private String currentTaskName;
private TaskInfo lastTaskInfo;
private int taskCount;
/** Total running time */
private long totalTimeMillis;
/**
* Construct a new stop watch. Does not start any task.
*/
public StopWatch() {
this("");
}
/**
* Construct a new stop watch with the given id.
* Does not start any task.
* @param id identifier for this stop watch.
* Handy when we have output from multiple stop watches
* and need to distinguish between them.
*/
/**
* Return the id of this stop watch, as specified on construction.
* @return the id (empty String by default)
* @since 4.2.2
* @see #StopWatch(String)
*/
public String getId() {
return this.id;
}
/**
* Determine whether the TaskInfo array is built over time. Set this to
* "false" when using a StopWatch for millions of intervals, or the task
* info structure will consume excessive memory. Default is "true".
*/
public void setKeepTaskList(boolean keepTaskList) {
this.keepTaskList = keepTaskList;
}
/**
* Start an unnamed task. The results are undefined if {@link #stop()}
* or timing methods are called without invoking this method.
* @see #stop()
*/
public void start() throws IllegalStateException {
start("");
}
/**
* Start a named task. The results are undefined if {@link #stop()}
* or timing methods are called without invoking this method.
* @param taskName the name of the task to start
* @see #stop()
*/
public void start(String taskName) throws IllegalStateException {
if (this.running) {
throw new IllegalStateException("Can't start StopWatch: it's already running"); }
this.running = true;
this.currentTaskName = taskName;
this.startTimeMillis = System.currentTimeMillis();
}
/**
* Stop the current task. The results are undefined if timing
* methods are called without invoking at least one pair
* {@code start()} / {@code stop()} methods.
* @see #start()
*/
public void stop() throws IllegalStateException {
if (!this.running) {
throw new IllegalStateException("Can't stop StopWatch: it's not running");
}
long lastTime = System.currentTimeMillis() - this.startTimeMillis;
this.totalTimeMillis += lastTime;
stTaskInfo = new TaskInfo(this.currentTaskName, lastTime);
if (this.keepTaskList) {
this.taskList.add(lastTaskInfo);
}
++this.taskCount;
this.running = false;
this.currentTaskName = null;
}
/**
* Return whether the stop watch is currently running.
* @see #currentTaskName()
*/
public boolean isRunning() {
return this.running;
}
* Return the name of the currently running task, if any.
* @since 4.2.2
* @see #isRunning()
*/
public String currentTaskName() {
return this.currentTaskName;
}
/**
* Return the time taken by the last task.
*/
public long getLastTaskTimeMillis() throws IllegalStateException {
if (stTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task interval"); }
return stTaskInfo.getTimeMillis();
}
/**
* Return the name of the last task.
*/
public String getLastTaskName() throws IllegalStateException {
if (stTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task name"); }
return stTaskInfo.getTaskName();
}
/**
* Return the last task as a TaskInfo object.
*/
public TaskInfo getLastTaskInfo() throws IllegalStateException {
if (stTaskInfo == null) {
throw new IllegalStateException("No tasks run: can't get last task info");
}
return stTaskInfo;
}
/**
* Return the total time in milliseconds for all tasks.
*/
public long getTotalTimeMillis() {
return this.totalTimeMillis;
}
/**
* Return the total time in seconds for all tasks.
*/
public double getTotalTimeSeconds() {
return this.totalTimeMillis / 1000.0;
}
/**
* Return the number of tasks timed.
*/
public int getTaskCount() {
return this.taskCount;
}
/**
* Return an array of the data for tasks performed.
*/
public TaskInfo[] getTaskInfo() {
if (!this.keepTaskList) {
throw new UnsupportedOperationException("Task info is not being kept!"); }
return this.taskList.toArray(new TaskInfo[this.taskList.size()]);
}
/**
* Return a short description of the total running time.
public String shortSummary() {
return "StopWatch '" + getId() + "': running time (millis) = " + getTotalTimeMillis();
}
/**
* Return a string with a table describing all tasks performed.
* For custom reporting, call getTaskInfo() and use the task info directly.
*/
public String prettyPrint() {
StringBuilder sb = new StringBuilder(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);
for (TaskInfo task : getTaskInfo()) {
sb.append(nf.format(task.getTimeMillis())).append(" ");
sb.append(pf.format(task.getTimeSeconds() / getTotalTimeSeconds())).append(" ");
sb.append(task.getTaskName()).append("\n");
}
}
return sb.toString();
}
/**
* Return an informative string describing all tasks performed
* For custom reporting, call {@code getTaskInfo()} and use the task info directly.
*/
@Override
public String toString() {
StringBuilder sb = new StringBuilder(shortSummary());
if (this.keepTaskList) {
for (TaskInfo task : getTaskInfo()) {
sb.append("; [").append(task.getTaskName()).append("] took ").append(task.getTimeMillis()); long percent = Math.round((100.0 * task.getTimeSeconds()) / getTotalTimeSeconds());
sb.append(" = ").append(percent).append("%");
}
}
else {
sb.append("; no task info kept");
}
return sb.toString();
}
/**
* Inner class to hold data about one task executed within the stop watch.
*/
public static final class TaskInfo {
private final String taskName;
private final long timeMillis;
TaskInfo(String taskName, long timeMillis) {
this.taskName = taskName;
this.timeMillis = timeMillis;
}
/**
* Return the name of this task.
*/
public String getTaskName() {
return this.taskName;
}
* Return the time in milliseconds this task took.
*/
public long getTimeMillis() {
return this.timeMillis;
}
/**
* Return the time in seconds this task took.
*/
public double getTimeSeconds() {
return (this.timeMillis / 1000.0);
}
}
}
下⾯写⼀个调⽤:
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,查看程序执⾏时间。

写法⼆(mons实现的计时器):
import java.util.concurrent.TimeUnit;
/**
* <p>
* <code>StopWatch</code> provides a convenient API for timings.
* </p>
*
* <p>
* To start the watch, call {@link #start()} or {@link StopWatch#createStarted()}. At this point you can:
* </p>
* <ul>
* <li>{@link #split()} the watch to get the time whilst the watch continues in the background. {@link #unsplit()} will
* remove the effect of the split. At this point, these three options are available again.</li>
* <li>{@link #suspend()} the watch to pause it. {@link #resume()} allows the watch to continue. Any time between the
* suspend and resume will not be counted in the total. At this point, these three options are available again.</li>
* <li>{@link #stop()} the watch to complete the timing session.</li>
* </ul>
* It is intended that the output methods {@link #toString()} and {@link #getTime()} should only be called after stop, * split or suspend, however a suitable result will be returned at other points.
* </p>
*
* <p>
* NOTE: As from v2.1, the methods protect against inappropriate calls. Thus you cannot now call stop before start, * resume before suspend or unsplit before split.
* </p>
*
* <p>
* 1. split(), suspend(), or stop() cannot be invoked twice<br>
* 2. unsplit() may only be called if the watch has been split()<br>
* 3. resume() may only be called if the watch has been suspend()<br>
* 4. start() cannot be called twice without calling reset()
* </p>
*
* <p>This class is not thread-safe</p>
*
* @since 2.0
*/
public class StopWatch {
private static final long NANO_2_MILLIS = 1000000L;
/**
* Provides a started stopwatch for convenience.
*
* @return StopWatch a stopwatch that's already been started.
*
* @since 3.5
*/
public static StopWatch createStarted() {
final StopWatch sw = new StopWatch();
sw.start();
return sw;
}
/**
* Enumeration type which indicates the status of stopwatch.
*/
private enum State {
UNSTARTED {
@Override
boolean isStarted() {
return false;
}
@Override
boolean isStopped() {
return true;
}
@Override
boolean isSuspended() {
return false;
}
},
RUNNING {
@Override
boolean isStarted() {
return true;
}
@Override
boolean isStopped() {
return false;
}
@Override
boolean isSuspended() {
return false;
}
},
STOPPED {
@Override
boolean isStarted() {
return false;
boolean isStopped() {
return true;
}
@Override
boolean isSuspended() {
return false;
}
},
SUSPENDED {
@Override
boolean isStarted() {
return true;
}
@Override
boolean isStopped() {
return false;
}
@Override
boolean isSuspended() {
return true;
}
};
/**
* <p>
* The method is used to find out if the StopWatch is started. A suspended * StopWatch is also started watch.
* </p>
* @return boolean
* If the StopWatch is started.
*/
abstract boolean isStarted();
/**
* <p>
* This method is used to find out whether the StopWatch is stopped. The * stopwatch which's not yet started and explicitly stopped stopwatch is
* considered as stopped.
* </p>
*
* @return boolean
* If the StopWatch is stopped.
*/
abstract boolean isStopped();
/**
* <p>
* This method is used to find out whether the StopWatch is suspended. * </p>
*
* @return boolean
* If the StopWatch is suspended.
*/
abstract boolean isSuspended();
}
/**
* Enumeration type which indicates the split status of stopwatch.
*/
private enum SplitState {
SPLIT,
UNSPLIT
}
/**
* The current running state of the StopWatch.
*/
private State runningState = State.UNSTARTED;
/**
* Whether the stopwatch has a split time recorded.
*/
private SplitState splitState = SplitState.UNSPLIT;
private long startTime;
/**
* The start time in Millis - nanoTime is only for elapsed time so we
* need to also store the currentTimeMillis to maintain the old
* getStartTime API.
*/
private long startTimeMillis;
/**
* The stop time.
*/
private long stopTime;
/**
* <p>
* Constructor.
* </p>
*/
public StopWatch() {
super();
}
/**
* <p>
* Start the stopwatch.
* </p>
*
* <p>
* This method starts a new timing session, clearing any previous values.
* </p>
*
* @throws IllegalStateException
* if the StopWatch is already running.
*/
public void start() {
if (this.runningState == State.STOPPED) {
throw new IllegalStateException("Stopwatch must be reset before being restarted. "); }
if (this.runningState != State.UNSTARTED) {
throw new IllegalStateException("Stopwatch already started. ");
}
this.startTime = System.nanoTime();
this.startTimeMillis = System.currentTimeMillis();
this.runningState = State.RUNNING;
}
/**
* <p>
* Stop the stopwatch.
* </p>
*
* <p>
* This method ends a new timing session, allowing the time to be retrieved.
* </p>
*
* @throws IllegalStateException
* if the StopWatch is not running.
*/
public void stop() {
if (this.runningState != State.RUNNING && this.runningState != State.SUSPENDED) { throw new IllegalStateException("Stopwatch is not running. ");
}
if (this.runningState == State.RUNNING) {
this.stopTime = System.nanoTime();
}
this.runningState = State.STOPPED;
}
/**
* <p>
* Resets the stopwatch. Stops it if need be.
* This method clears the internal values to allow the object to be reused.
* </p>
*/
public void reset() {
this.runningState = State.UNSTARTED;
this.splitState = SplitState.UNSPLIT;
}
/**
* <p>
* Split the time.
* </p>
*
* <p>
* This method sets the stop time of the watch to allow a time to be extracted. The start time is unaffected,
* enabling {@link #unsplit()} to continue the timing from the original start point.
* </p>
*
* @throws IllegalStateException
* if the StopWatch is not running.
*/
public void split() {
if (this.runningState != State.RUNNING) {
throw new IllegalStateException("Stopwatch is not running. ");
}
this.stopTime = System.nanoTime();
this.splitState = SplitState.SPLIT;
}
/**
* <p>
* Remove a split.
* </p>
*
* <p>
* This method clears the stop time. The start time is unaffected, enabling timing from the original start point to * continue.
* </p>
*
* @throws IllegalStateException
* if the StopWatch has not been split.
*/
public void unsplit() {
if (this.splitState != SplitState.SPLIT) {
throw new IllegalStateException("Stopwatch has not been split. ");
}
this.splitState = SplitState.UNSPLIT;
}
/**
* <p>
* Suspend the stopwatch for later resumption.
* </p>
*
* <p>
* This method suspends the watch until it is resumed. The watch will not include time between the suspend and * resume calls in the total time.
* </p>
*
* @throws IllegalStateException
* if the StopWatch is not currently running.
*/
public void suspend() {
if (this.runningState != State.RUNNING) {
throw new IllegalStateException("Stopwatch must be running to suspend. ");
}
this.stopTime = System.nanoTime();
this.runningState = State.SUSPENDED;
}
/**
* <p>
* Resume the stopwatch after a suspend.
* This method resumes the watch after it was suspended. The watch will not include time between the suspend and * resume calls in the total time.
* </p>
*
* @throws IllegalStateException
* if the StopWatch has not been suspended.
*/
public void resume() {
if (this.runningState != State.SUSPENDED) {
throw new IllegalStateException("Stopwatch must be suspended to resume. ");
}
this.startTime += System.nanoTime() - this.stopTime;
this.runningState = State.RUNNING;
}
/**
* <p>
* Get the time on the stopwatch.
* </p>
*
* <p>
* This is either the time between the start and the moment this method is called, or the amount of time between
* start and stop.
* </p>
*
* @return the time in milliseconds
*/
public long getTime() {
return getNanoTime() / NANO_2_MILLIS;
}
/**
* <p>
* Get the time on the stopwatch in the specified TimeUnit.
* </p>
*
* <p>
* This is either the time between the start and the moment this method is called, or the amount of time between
* start and stop. The resulting time will be expressed in the desired TimeUnit with any remainder rounded down.
* For example, if the specified unit is {@code TimeUnit.HOURS} and the stopwatch time is 59 minutes, then the
* result returned will be {@code 0}.
* </p>
*
* @param timeUnit the unit of time, not null
* @return the time in the specified TimeUnit, rounded down
* @since 3.5
*/
public long getTime(final TimeUnit timeUnit) {
return timeUnit.convert(getNanoTime(), TimeUnit.NANOSECONDS);
}
/**
* <p>
* Get the time on the stopwatch in nanoseconds.
* </p>
*
* <p>
* This is either the time between the start and the moment this method is called, or the amount of time between
* start and stop.
* </p>
*
* @return the time in nanoseconds
* @since 3.0
*/
public long getNanoTime() {
if (this.runningState == State.STOPPED || this.runningState == State.SUSPENDED) {
return this.stopTime - this.startTime;
} else if (this.runningState == State.UNSTARTED) {
return 0;
} else if (this.runningState == State.RUNNING) {
return System.nanoTime() - this.startTime;
}
throw new RuntimeException("Illegal running state has occurred.");
/**
* <p>
* Get the split time on the stopwatch.
* </p>
*
* <p>
* This is the time between start and latest split.
* </p>
*
* @return the split time in milliseconds
*
* @throws IllegalStateException
* if the StopWatch has not yet been split.
* @since 2.1
*/
public long getSplitTime() {
return getSplitNanoTime() / NANO_2_MILLIS;
}
/**
* <p>
* Get the split time on the stopwatch in nanoseconds.
* </p>
*
* <p>
* This is the time between start and latest split.
* </p>
*
* @return the split time in nanoseconds
*
* @throws IllegalStateException
* if the StopWatch has not yet been split.
* @since 3.0
*/
public long getSplitNanoTime() {
if (this.splitState != SplitState.SPLIT) {
throw new IllegalStateException("Stopwatch must be split to get the split time. ");
}
return this.stopTime - this.startTime;
}
/**
* Returns the time this stopwatch was started.
*
* @return the time this stopwatch was started
* @throws IllegalStateException
* if this StopWatch has not been started
* @since 2.4
*/
public long getStartTime() {
if (this.runningState == State.UNSTARTED) {
throw new IllegalStateException("Stopwatch has not been started");
}
// System.nanoTime is for elapsed time
return this.startTimeMillis;
}
/**
* <p>
* Gets a summary of the time that the stopwatch recorded as a string.
* </p>
*
* <p>
* The format used is ISO 8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>. * </p>
*
* @return the time as a String
*/
@Override
public String toString() {
return DurationFormatUtils.formatDurationHMS(getTime());
}
/**
* <p>
* Gets a summary of the split time that the stopwatch recorded as a string.
* </p>
*
* <p>
* The format used is ISO 8601-like, <i>hours</i>:<i>minutes</i>:<i>seconds</i>.<i>milliseconds</i>. * </p>
*
* @return the split time as a String
* @since 2.1
*/
public String toSplitString() {
return DurationFormatUtils.formatDurationHMS(getSplitTime());
}
/**
* <p>
* The method is used to find out if the StopWatch is started. A suspended
* StopWatch is also started watch.
* </p>
*
* @return boolean
* If the StopWatch is started.
* @since 3.2
*/
public boolean isStarted() {
return runningState.isStarted();
}
/**
* <p>
* This method is used to find out whether the StopWatch is suspended.
* </p>
*
* @return boolean
* If the StopWatch is suspended.
* @since 3.2
*/
public boolean isSuspended() {
return runningState.isSuspended();
}
/**
* <p>
* This method is used to find out whether the StopWatch is stopped. The
* stopwatch which's not yet started and explicitly stopped stopwatch is
* considered as stopped.
* </p>
*
* @return boolean
* If the StopWatch is stopped.
* @since 3.2
*/
public boolean isStopped() {
return runningState.isStopped();
}
}
写法三(Scala函数写法):
import org.slf4j.LoggerFactory
/**
* 类功能描述:Debug⽇志追踪
*
* @author barry create at 18-8-29 下午3:41
* @version 1.0.0
*/
object Debug {
val LOGGER = LoggerFactory.getLogger(getClass)
val counter = collection.mutable.Map[String, Int]() // label -> count
val times = collection.mutable.Map[String, Long]() // label - time(ns)
/**
*追踪代码块
* @param label 标签名
* @param codeBlock 代码块
* @tparam T 返回结果类型
* @return
*/
def trace[T](label: String)(codeBlock: => T) = {
val t0 = System.nanoTime()
val result = codeBlock
val t1 = System.nanoTime()
counter.get(label).map(_counter => counter.put(label, _counter + 1)).orElse(counter.put(label, 1))
times.get(label).map(cost => times.put(label, cost + (t1 - t0))).orElse(times.put(label, t1 - t0))
result
}
/**
* 打印⽇志
*/
def info(): Unit = {
LOGGER.warn("FinallyDone...")
LOGGER.warn(s"counter:${counter}")
LOGGER.warn(s"times:${times.map { case (label, cost) => (label, cost / 1000000)}}ms")
}
/**
* 重新计数
*/
def reset(): Unit = {
counter.clear()
times.clear()
}
}
参考下⾯测试代码:
java版本:
/**
* @author WangXueXing create at 19-7-31 下午1:46
* @version 1.0.0
*/
public class StopWatchDemo {
public static void main(String[] args){
Debug.trace("⽅法1调⽤次数及⽤时", ()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "";
});
Debug.trace("⽅法1调⽤次数及⽤时", ()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "";
});
Debug.trace("⽅法2调⽤次数及⽤时", ()->{
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return 10;
});
();
}
}
输出结果:
15:29:32.228 [main] WARN test.Debug$ - FinallyDone...
15:29:32.361 [main] WARN test.Debug$ - counter:Map(⽅法2调⽤次数及⽤时 -> 1, ⽅法1调⽤次数及⽤时 -> 2)
15:29:32.364 [main] WARN test.Debug$ - times:Map(⽅法2调⽤次数及⽤时 -> 2000, ⽅法1调⽤次数及⽤时 -> 4000)ms
scala版本:
/**
* @author WangXueXing create at 19-8-1 下午3:40
* @version 1.0.0
*/
object StopWatchTest {
def main(args: Array[String]): Unit = {
Debug.trace("⽅法1调⽤次数及⽤时")( Thread.sleep(200))
Debug.trace("⽅法1调⽤次数及⽤时")( Thread.sleep(200))
Debug.trace("⽅法2调⽤次数及⽤时")( Thread.sleep(200))
()
}
}
输出结果:
15:43:58.601 [main] WARN test.stopwatch.Debug$ - FinallyDone...
15:43:58.735 [main] WARN test.stopwatch.Debug$ - counter:Map(⽅法2调⽤次数及⽤时 -> 1, ⽅法1调⽤次数及⽤时 -> 2)
15:43:58.739 [main] WARN test.stopwatch.Debug$ - times:Map(⽅法2调⽤次数及⽤时 -> 200, ⽅法1调⽤次数及⽤时 -> 400)ms
对⽐java版本与scala版本,是不是看到scala的简洁及强⼤了吧!
以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

相关文档
最新文档