StopWatch是位于org.springframework.util包下的一個(gè)工具類,通過它可方便的對(duì)程序部分代碼進(jìn)行計(jì)時(shí)(ms級(jí)別),適用于同步單線程代碼塊。
正常情況下,我們?nèi)绻枰茨扯未a的執(zhí)行耗時(shí),會(huì)通過如下的方式進(jìn)行查看:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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執(zhí)行耗時(shí):" + (end - start)); System.out.println( "某某2執(zhí)行耗時(shí):" + (end2 - start2)); } |
1
2
3
|
運(yùn)行結(jié)果: 某某1執(zhí)行耗時(shí):105 某某2執(zhí)行耗時(shí):203 |
該種方法通過獲取執(zhí)行完成時(shí)間與執(zhí)行開始時(shí)間的差值得到程序的執(zhí)行時(shí)間,簡(jiǎn)單直接有效,但想必寫多了也是比較煩人的,尤其是碰到不可描述的代碼時(shí),會(huì)更加的讓人忍不住多寫幾個(gè)bug聊表敬意,而且該結(jié)果也不夠直觀,此時(shí)會(huì)想是否有一個(gè)工具類,提供了這些方法,或者自己寫個(gè)工具類,剛好可以滿足這種場(chǎng)景,并且把結(jié)果更加直觀的展現(xiàn)出來。
首先我們的需求如下:
- 記錄開始時(shí)間點(diǎn)
- 記錄結(jié)束時(shí)間點(diǎn)
- 輸出執(zhí)行時(shí)間及各個(gè)時(shí)間段的占比
根據(jù)該需求,我們可直接使用org.springframework.util包下的一個(gè)工具類StopWatch,通過該工具類,我們對(duì)上述代碼做如下改造:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
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()); } |
1
2
3
4
5
6
7
8
|
運(yùn)行結(jié)果: sw.prettyPrint()~~~~~~~~~~~~~~~~~ StopWatch 'test': running time (millis) = 308 ----------------------------------------- ms % Task name ----------------------------------------- 00104 034% task1 00204 066% task2 |
start開始記錄,stop停止記錄,然后通過StopWatch的prettyPrint方法,可直觀的輸出代碼執(zhí)行耗時(shí),以及執(zhí)行時(shí)間百分比,瞬間感覺比之前的方式高大上了一個(gè)檔次。
除此之外,還有以下兩個(gè)方法shortSummary,getTotalTimeMillis,查看程序執(zhí)行時(shí)間。
運(yùn)行代碼及結(jié)果:
1
2
3
4
5
6
7
8
9
|
System.out.println( "sw.shortSummary()~~~~~~~~~~~~~~~~~" ); System.out.println(sw.shortSummary()); System.out.println( "sw.getTotalTimeMillis()~~~~~~~~~~~~~~~~~" ); System.out.println(sw.getTotalTimeMillis()); 運(yùn)行結(jié)果 sw.shortSummary()~~~~~~~~~~~~~~~~~ StopWatch 'test' : running time (millis) = 308 sw.getTotalTimeMillis()~~~~~~~~~~~~~~~~~ 308 |
其實(shí)以上內(nèi)容在該工具類中實(shí)現(xiàn)也極其簡(jiǎn)單,通過start與stop方法分別記錄開始時(shí)間與結(jié)束時(shí)間,其中在記錄結(jié)束時(shí)間時(shí),會(huì)維護(hù)一個(gè)鏈表類型的tasklist屬性,從而使該類可記錄多個(gè)任務(wù),最后的輸出也僅僅是對(duì)之前記錄的信息做了一個(gè)統(tǒng)一的歸納輸出,從而使結(jié)果更加直觀的展示出來。
StopWatch優(yōu)缺點(diǎn):
優(yōu)點(diǎn):
- spring自帶工具類,可直接使用
- 代碼實(shí)現(xiàn)簡(jiǎn)單,使用更簡(jiǎn)單
- 統(tǒng)一歸納,展示每項(xiàng)任務(wù)耗時(shí)與占用總時(shí)間的百分比,展示結(jié)果直觀性能消耗相對(duì)較小,并且最大程度的保證了start與stop之間的時(shí)間記錄的準(zhǔn)確性
- 可在start時(shí)直接指定任務(wù)名字,從而更加直觀的顯示記錄結(jié)果
缺點(diǎn):
- 一個(gè)StopWatch實(shí)例一次只能開啟一個(gè)task,不能同時(shí)start多個(gè)task,并且在該task未stop之前不能start一個(gè)新的task,必須在該task stop之后才能開啟新的task,若要一次開啟多個(gè),需要new不同的StopWatch實(shí)例
- 代碼侵入式使用,需要改動(dòng)多處代碼
spring中StopWatch源碼實(shí)現(xiàn)如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
|
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; } } } |
到此這篇關(guān)于Spring計(jì)時(shí)器stopwatch使用詳解的文章就介紹到這了,更多相關(guān)Spring計(jì)時(shí)器stopwatch內(nèi)容請(qǐng)搜索服務(wù)器之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持服務(wù)器之家!
原文鏈接:https://blog.csdn.net/gxs1688/article/details/87185030