1概要

この記事では、Javaで経過時間を測定する方法について説明します。

これは簡単に思えるかもしれませんが、注意しなければならない落とし穴がいくつかあります。

経過時間を測定する機能を提供する標準的なJavaクラスと外部パッケージを調べます。


2簡単な測定


2.1.

currentTimeMillis()


Javaで経過時間を測定するという要件に遭遇したときには、次のようにします。

long start = System.currentTimeMillis();//...
long finish = System.currentTimeMillis();
long timeElapsed = finish - start;

コードを見れば、それは完全に理にかなっています。開始時にタイムスタンプを取得し、コードが終了したときに別のタイムスタンプを取得します。経過時間は、これら2つの値の差です。

しかしながら、** System.currentTimeMillis()がウォールクロック時間を測定するので、結果は不正確になる可能性があります。システム時間を変更すると結果に影響が出るか、うるう秒が結果を乱すことがあります。


2.2.

nanoTime()



java.lang.System

クラスのもう1つのメソッドは

nanoTime()

です。

Javaのドキュメント

を見ると、次のようになります。


“この方法は経過時間の測定にのみ使用でき、システムや壁時計の時間に関するその他の概念とは関係ありません。”

それを使ってみましょう:

long start = System.nanoTime();//...
long finish = System.nanoTime();
long timeElapsed = finish - start;

コードは基本的に以前と同じです。唯一の違いは、タイムスタンプを取得するために使用されるメソッド –

currentTimeMillis()

ではなく

nanoTime()

です。


nanoTime()

は、明らかにナノ秒単位で時間を返します。したがって、経過時間が異なる時間単位で測定されている場合は、それに応じて変換する必要があります。

たとえば、ミリ秒に変換するには、結果をナノ秒単位で1.000.000で割る必要があります。


nanoTime()

のもう1つの落とし穴は、たとえそれがナノ秒の精度を提供するとしても、それはナノ秒の解像度を保証するものではないということです。

値が更新される頻度

ただし、解像度が少なくとも

currentTimeMillis()

の解像度と同等になることは保証されます。


3 Java 8

Java 8を使用している場合 – 新しい


java.time.Instant


およびhttps:/を試すことができます。/docs.oracle.com/javase/8/docs/api/java/time/Duration.html[

java.time.Duration

]クラス。どちらも不変でスレッドセーフであり、新しい

java.time

API内のすべてのクラスと同様に、独自のタイムスケール

Java Time-Scale

を使用します。


3.1. Javaタイムスケール

時間を測定する伝統的な方法は、1日を60秒60分の24時間に分割することです。これは1日86.400秒になります。しかし、太陽の日はいつも同じくらい長くはありません。

UTCタイムスケールでは、実際には1日に86.399または86.401 SI秒を設定できます。 SI秒は科学的な「国際標準秒」であり、セシウム133原子の放射期間によって定義されます。これは日を太陽と揃えるために必要です。

  • Java Time-Scaleは各暦日を秒単位** と呼ばれる正確に86.400の細分に分割します。うるう秒はありません。


3.2.

インスタンス

クラス


Instant

クラスはタイムライン上のインスタントを表します。基本的には、

1970-01-01T00:00:00Z

という標準のJavaエポック以降の数値のタイムスタンプです。

現在のタイムスタンプを取得するために、

Instant.now()

staticメソッドを使用できます。このメソッドでは、オプションのhttps://docs.oracle.com/javase/8/docs/api/java/time/Clock.html[

Clock

]パラメータを渡すことができます。

省略すると、デフォルトのタイムゾーンのシステムクロックが使用されます。

  • 前の例のように、開始時間と終了時間を2つの変数に格納できます。** 次に、両方の時点間の経過時間を計算できます。

2つの

Instant

オブジェクト間の期間を取得するには、さらに

Duration

クラスを使用します。これは

between()

メソッドです。最後に、

Duration

をミリ秒に変換する必要があります。

Instant start = Instant.now();//CODE HERE
Instant finish = Instant.now();
long timeElapsed = Duration.between(start, finish).toMillis();


4

StopWatch


ライブラリに移ると、Apache Commons Langは経過時間の測定に使用できる

StopWatch

クラスを提供します。


4.1. Mavenの依存関係

pom.xmlを更新することで最新版を入手できます。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.7</version>
</dependency>

依存関係の最新バージョンはhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22org.apache.commons%22%20AND%20a%3A%22commons-lang3%で確認できます。 22[ここ]


4.2.

StopWatch


で経過時間を測定する

まず最初に、クラスのインスタンスを取得する必要があります。それから経過時間を単純に測定できます。

StopWatch watch = new StopWatch();
watch.start();

監視を実行したら、ベンチマークしたいコードを実行し、最後に

stop()

メソッドを呼び出します。

最後に、実際の結果を取得するために、

getTime()

を呼び出します。

watch.stop();
System.out.println("Time Elapsed: " + watch.getTime());//Prints: Time Elapsed: 2501


  • StopWatch

    には、測定を一時停止または再開するために使用できるヘルパーメソッドがいくつかあります。

最後に、このクラスはスレッドセーフではないことに注意してください。


5結論

Javaで時間を測定する方法はたくさんあります。

currentTimeMillis()

を使用して、非常に “伝統的な”(そして不正確な)方法を説明しました。

さらに、Apache Commonの

StopWatch

を調べ、Java 8で利用可能な新しいクラスを調べました。

全体として、経過時間の簡単で正しい測定には、

nanoTime()

メソッドで十分です。

currentTimeMillis()

よりも入力が短くなります。

ただし、手動で時間を測定するのではなく、適切なベンチマークを行うために、Java Microbenchmark Harness(JMH)のようなフレームワークを使用できます。このトピックはこの記事の範囲を超えていますが、リンク:/java-microbenchmark-harness[ここ]を調べました。

最後に、いつものように、ディスカッション中に使用されたコードはhttps://github.com/eugenp/tutorials/tree/master/java-dates[GitHubについて]にあります。