12 定期イベント

PeriodicSample.javaの例では、作成されて開始されたスレッドの合計数を1秒ごとに記録するStartedThreadCountという名前の定期イベントが作成されます。

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

import jdk.jfr.Event;
import jdk.jfr.FlightRecorder;
import jdk.jfr.Label;
import jdk.jfr.Name;
import jdk.jfr.Period;

public class PeriodicSample {

    private static ThreadMXBean tBean =
        ManagementFactory.getThreadMXBean();

    @Name("com.oracle.StartedThreadCount")
    @Label("Total number of started threads")
    @Period("1 s")
    static class StartedThreadCount extends Event {
        long totalStartedThreadCount;
    }

    public static void main(String[] args) throws InterruptedException {

        Runnable hook = () -> {
            StartedThreadCount event = new StartedThreadCount();
            event.totalStartedThreadCount =
                tBean.getTotalStartedThreadCount();
            event.commit();
        };

        FlightRecorder.addPeriodicEvent(StartedThreadCount.class, hook);

        for (int i = 0; i < 4; i++) {
            Thread.sleep(1500);
            Thread t = new Thread();
            t.start();
        }
      
        FlightRecorder.removePeriodicEvent(hook);
    }
}

次のコマンドを使用して、PeriodicSampleを実行します:

java -XX:StartFlightRecording:filename=periodic.jfr PeriodicSample.java
jfr print --events EveryTwoSeconds periodicsample.jfr 

最後のコマンドでは、次のような出力が表示されます:

com.oracle.StartedThreadCount {
  startTime = 00:59:40.769
  totalStartedThreadCount = 12
    ...
}

com.oracle.StartedThreadCount {
  startTime = 00:59:41.816
  totalStartedThreadCount = 12
    ...
}

com.oracle.StartedThreadCount {
  startTime = 00:59:42.866
  totalStartedThreadCount = 13
    ...
}

com.oracle.StartedThreadCount {
  startTime = 00:59:43.918
  totalStartedThreadCount = 14
    ...
}

com.oracle.StartedThreadCount {
  startTime = 00:59:44.962
  totalStartedThreadCount = 14
    ...
}

定期イベントを作成するには、次の2つのステップを実行します:

  1. @Period注釈を使用してイベントを発行する頻度を指定します:
    @Name("com.oracle.StartedThreadCount")
    @Label("Total number of started threads")
    @Period("1 s")
    static class StartedThreadCount extends Event {
        long totalStartedThreadCount;
    }

    期間の有効な単位は、nsusmssmhおよびdです。

    また、次のいすれかを指定することも可能です:

    • everyChunk: 定期イベントは記録中に少なくとも1回発行されます。
    • beginChunk: 定期イベントは記録の開始時に発行されます。
    • endChunk: 定期イベントは記録の終了時に発行されます。
  2. FlightRecorder.addPeriodicEvent(Class<? extends Event>, Runnable)静的メソッドを使用して、定期イベントを追加します。1つ目の引数は、定期イベントのクラス名です。2つ目の引数はコールバック・メソッドで、イベントを作成してコミットするラムダ式で表されています。
    Runnable hook = () -> {
        StartedThreadCount event = new StartedThreadCount();
        event.totalStartedThreadCount =
            tBean.getTotalStartedThreadCount();
        event.commit();
    };
    
    FlightRecorder.addPeriodicEvent(StartedThreadCount.class, hook);

メソッドFlightRecorder.removePeriodicEvent(Runnable)は、定期イベントに関連付けられているラムダ式を削除します。ほとんどの場合、このメソッドは必要ありません。Recording.disable(Class<? extends Event>)を呼び出せば、定期イベントを無効にできます。ただし、removePeriodicEventを呼び出す理由の1つは、メモリー・リークの回避です。たとえば、データのロードとアンロードが行われたアプリケーション・サーバーがあるとします。サーバーがロードしてアンロードしたデータをコールバック・メソッドが参照していると、そのデータのガベージ・コレクションが行われないことがあります。データがアンロードされるときにコールバック・メソッドを削除すれば、これを回避できます。