2019.04.05
ストップウォッチ その2
ストップウォッチのクラス
ナノ秒単位で時間を測定できるストップウォッチのクラスを作成しました。
StopWatch2.java
001 002 003 004 005 006 007 008 009 010 011 012 013 014 015 016 017 018 019 020 021 022 023 024 025 026 027 028 029 030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045 046 047 048 049 050 051 052 053 054 055 056 057 058 059 060 061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079 080 081 082 083 084 085 086 087 088 089 090 091 092 093 094 095 096 097 098 099 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
// ストップウォッチクラスを作成 class MyStopWatch2 { // 開始時間に初期値-1を代入 private long ts = -1; // 終了時間に初期値-1を代入 private long te = -1; // 計測時間に初期値0を代入 private long tresult = 0; // 一時停止するまでの時間に初期値-1を代入 private long tresult_temp = -1; // 開始メソッド public void start() { // 計測時間に初期値0を代入 tresult = 0; // 一時停止までの時間に初期値-1を代入 tresult_temp = -1; // 開始時間を代入 ts = System.nanoTime(); } // 停止メソッド public void stop() { // start()が呼ばれているか? if ( 0 > ts ) return; // 終了時間を代入 te = System.nanoTime(); // 計測時間を代入 if ( 0 <= tresult_temp ) // 一時停止あり tresult = te - ts + tresult_temp; else // 一時停止なし tresult = te - ts; } // クリアメソッド public void clear() { // 開始終了時間に初期値-1を代入 ts = -1; te = -1; // 計測時間に初期値0を代入 tresult = 0; // 一時停止までの時間に初期値-1を代入 tresult_temp = -1; } // 一時停止メソッド public void suspend() { // start()が呼ばれているか? if ( 0 > ts ) return; // 終了時間を代入 te = System.nanoTime(); // 一時停止するまでの時間を計算 tresult_temp += te - ts; // 計測時間に一時停止するまでの時間を代入 tresult = tresult_temp; // 開始終了時間に初期値-1を代入 ts = -1; te = -1; } // 再開メソッド public void resume() { // 一時停止中か? if ( ( 0 <= tresult_temp ) && ( 0 > ts ) ) { // 一時停止中 // 開始時間を代入 ts = System.nanoTime(); } } // 計測時間をナノ秒で返す public long nanotime() { return tresult; } } // メイン public class StopWatch2 { public static void main( String[] args ) { // ストップウォッチクラスを作成 MyStopWatch2 sw = new MyStopWatch2(); try { // スタート sw.start(); // 500ミリ秒停止 Thread.sleep( 500 ); // 一時停止 sw.suspend(); // 300ミリ秒停止 Thread.sleep( 300 ); // 再開 sw.resume(); // 200ミリ秒停止 Thread.sleep( 200 ); // 一時停止 sw.suspend(); // 100ミリ秒停止 Thread.sleep( 100 ); // 再開 sw.resume(); // 200ミリ秒停止 Thread.sleep( 200 ); // ストップ sw.stop(); // 時間計測結果を表示 // 計測時間をナノ秒で取得 long tnsec = sw.nanotime(); // 処理時間 ミリ秒 double tmsec = (double)tnsec / 1000000.0; // 処理時間 秒 double tsec = tmsec / 1000.0; System.out.println( "時間 : " + tnsec + "ナノ秒 " + tmsec + "ミリ秒 " + tsec + "秒" ); } catch( InterruptedException e ) { return; } } }
コンパイル ソースコードが「ANSI」の場合
C:\talavax\javasample>javac -encoding sjis StopWatch2.java
コンパイル ソースコードが「UTF-8」の場合
C:\talavax\javasample>javac StopWatch2.java
実行
C:\talavax\javasample>java StopWatch2
実行結果
時間 : 900112001ナノ秒 900.112001ミリ秒 0.900112001秒
この結果から、プログラム中に複数あるThread.sleepうち、suspendメソッドとresumeメソッドの間の時間が出力結果に反映されていないことが確認できます。
Javaソースコードの解説
それでは、ここからストップウォッチのソースコードを解説していきます。
001 002
// ストップウォッチクラスを作成 class MyStopWatch2 {
クラス名を、StopWatch2としています。
003 004 005 006 007 008 009 010 011 012 013
// 開始時間に初期値-1を代入 private long ts = -1; // 終了時間に初期値-1を代入 private long te = -1; // 計測時間に初期値0を代入 private long tresult = 0; // 一時停止するまでの時間に初期値-1を代入 private long tresult_temp = -1;
メンバ変数を宣言しています。tsとteは、それぞれ時間計測の開始時間と終了時間を代入するlong型の変数で、初期値はどちらも-1です。tresultは、計測結果を代入するlong型の変数で、初期値は0です。tresult_tempは、一時停止した時間までの計測結果を代入するlong型の変数で、初期値は-1です。
016 017 018 019 020 021 022 023 024 025 026 027
// 開始メソッド public void start() { // 計測時間に初期値0を代入 tresult = 0; // 一時停止までの時間に初期値-1を代入 tresult_temp = -1; // 開始時間を代入 ts = System.nanoTime(); }
start()は、開始メソッドでStartボタンを意味します。計測時間tresultに0、一時停止までの時間result_tempに-1、開始時間tsにシステムタイマーの値を代入しています。System.nanoTime()でナノ秒単位のシステムタイマーを取得することができます。
System.nanoTimeメソッド
public static long nanoTime()
・システムタイマーの値をナノ秒単位で返します。 パラメータ なし 戻り値 システムタイマーの現在の値をナノ秒単位で返します。
開始時間ts=-1は、時間計測が開始していない状態で、一時停止までの時間result_temp=-1は、一時停止(suspend)が一度も呼ばれていない状態です。
030 031 032 033 034 035 036 037 038 039 040 041 042 043 044 045
public void stop() { // start()が呼ばれているか? if ( 0 > ts ) return; // 終了時間を代入 te = System.nanoTime(); // 計測時間を代入 if ( 0 <= tresult_temp ) // 一時停止あり tresult = te - ts + tresult_temp; else // 一時停止なし tresult = te - ts; }
stop()は、終了メソッドでStopボタンを意味します。開始時間tsが0未満であればstart()メソッドが呼ばれていないのでメソッドをreturn文で抜けます。結果として計測時間tresultは0となります。開始時間tsが0以上の場合、終了時間teにシステムタイマーの値を代入しします。次に計測時間tresultに値を代入します。その値は、一時停止した時間が有る場合( 0 <= tresult_temp )には、計測時間tresultに( te - ts ) + tresult_tempを代入します。無い場合には、計測時間tresultに( te - ts )を代入します。
047 048 049 050 051 052 053 054 055 056 057 058 059
// クリアメソッド public void clear() { // 開始終了時間に初期値-1を代入 ts = -1; te = -1; // 計測時間に初期値0を代入 tresult = 0; // 一時停止までの時間に初期値-1を代入 tresult_temp = -1; }
clear()は、クリアメソッドでResetボタンを意味します。開始時間tsと終了時間teに-1、計測結果tresultに0、一時停止までの時間tresult_tempに0を代入しています。
061 062 063 064 065 066 067 068 069 070 071 072 073 074 075 076 077 078 079
// 一時停止メソッド public void suspend() { // start()が呼ばれているか? if ( 0 > ts ) return; // 終了時間を代入 te = System.nanoTime(); // 一時停止するまでの時間を計算 tresult_temp += te - ts; // 計測時間に一時停止するまでの時間を代入 tresult = tresult_temp; // 開始終了時間に初期値-1を代入 ts = -1; te = -1; }
suspend()は、一時停止メソッドです。開始時間tsが0未満であればstart()メソッドが呼ばれていないのでメソッドをreturn文で抜けます。開始時間tsが0以上の場合、終了時間teにシステムタイマーの値を代入しします。次に、一時停止するまでの時間tresult_tempに( te - ts )を足し、計測結果tresultにtresult_tempを値を代入します。その後、開始時間tsと終了時間tsに-1を代入しています。
081 082 083 084 085 086 087 088 089 090
// 再開メソッド public void resume() { // 一時停止中か? if ( ( 0 <= tresult_temp ) && ( 0 > ts ) ) { // 一時停止中 // 開始時間を代入 ts = System.nanoTime(); } }
resume()は、再開メソッドです。一時停止するまでの時間tresult_tempが0以上で、開始時間tsが0未満であれば一時停止中なので、開始時間tsにシステムタイマーの値を代入しています。これで計測が再開された状態になります。
092 093 094 095 096
// 計測時間をナノ秒で返す public long nanotime() { return tresult; }
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
// メイン public class StopWatch2 { public static void main( String[] args ) { // ストップウォッチクラスを作成 MyStopWatch2 sw = new MyStopWatch2(); try { // スタート sw.start(); // 500ミリ秒停止 Thread.sleep( 500 ); // 一時停止 sw.suspend(); // 300ミリ秒停止 Thread.sleep( 300 ); // 再開 sw.resume(); // 200ミリ秒停止 Thread.sleep( 200 ); // 一時停止 sw.suspend(); // 100ミリ秒停止 Thread.sleep( 100 ); // 再開 sw.resume(); // 200ミリ秒停止 Thread.sleep( 200 ); // ストップ sw.stop(); // 時間計測結果を表示 // 計測時間をナノ秒で取得 long tnsec = sw.nanotime(); // 処理時間 ミリ秒 double tmsec = (double)tnsec / 1000000.0; // 処理時間 秒 double tsec = tmsec / 1000.0; System.out.println( "時間 : " + tnsec + "ナノ秒 " + tmsec + "ミリ秒 " + tsec + "秒" ); } catch( InterruptedException e ) { return; } } }
startメソッドとstopメソッドの間で、Thread.sleepを複数回実行しています。ここで、一時停止(suspendメソッド)と再開(resumeメソッド)で囲まれたThread.sleepの値は、最終的な計測結果に反映されていないことを確認してみてください。
Thread.sleepはtry { ~ } catchの間に書く必要があるので、このサンプルソースでは106行~152行の間をtry { ~ }で大きく囲んでいます。
以上です。