CodeBlanks Logo Icon CodeBlanks

Performance layer

Write performance measurement with JMH and GC tuning.

The performance measurement layer

The performance layer wraps the reactive publish with timing. A TimedPublisher wraps a SimplePublisher delegate; publish takes System.nanoTime() before and after and computes the elapsed time. This is the decorator pattern.

Since the timing varies, instead of printing the raw duration we print a fixed marker that says the measurement was done. This keeps the output deterministic.

The decorator pattern

Before wrapping SimplePublisher, TimedPublisher takes it in its constructor and stores it in a delegate field. When publish is called it first measures, then calls the delegate's publish. This is the decorator pattern: it changes object behaviour by wrapping.

The decorator uses composition instead of inheritance. That makes it flexible; it can wrap any publisher.

Practice Write the TimedPublisher class

Add a class TimedPublisher to the structure above with a SimplePublisher delegate field and a TimedPublisher(SimplePublisher delegate) constructor. Its void publish(String item) method first does long start = System.nanoTime();, then delegate.publish(item);, then long elapsed = System.nanoTime() - start; and prints System.out.println("elapsed measured: " + (elapsed >= 0));. In main create SimplePublisher p = new SimplePublisher();, add a subscriber and call new TimedPublisher(p).publish("hello");.

Starter code

Main.java
@interface Service {}

@Service
class HelloService {
    String greet() { return "hello"; }
}

interface Subscriber {
    void onNext(String item);
}

class SimplePublisher {
    java.util.List<Subscriber> subs = new java.util.ArrayList<>();
    void subscribe(Subscriber s) { subs.add(s); }
    void publish(String item) {
        for (Subscriber s : subs) s.onNext(item);
    }
}

public class Main {
    public static void main(String[] args) {
        SimplePublisher p = new SimplePublisher();
        p.subscribe(s -> System.out.println("got: " + s));
        p.publish("hello");
    }
}

Sample solution

Main.java
@interface Service {}

@Service
class HelloService {
    String greet() { return "hello"; }
}

interface Subscriber {
    void onNext(String item);
}

class SimplePublisher {
    java.util.List<Subscriber> subs = new java.util.ArrayList<>();
    void subscribe(Subscriber s) { subs.add(s); }
    void publish(String item) {
        for (Subscriber s : subs) s.onNext(item);
    }
}

class TimedPublisher {
    SimplePublisher delegate;
    TimedPublisher(SimplePublisher delegate) {
        this.delegate = delegate;
    }
    void publish(String item) {
        long start = System.nanoTime();
        delegate.publish(item);
        long elapsed = System.nanoTime() - start;
        System.out.println("elapsed measured: " + (elapsed >= 0));
    }
}

public class Main {
    public static void main(String[] args) {
        SimplePublisher p = new SimplePublisher();
        p.subscribe(s -> System.out.println("got: " + s));
        new TimedPublisher(p).publish("hello");
    }
}

Expected output

got: hello
elapsed measured: true

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 What does the performance layer measure?

  • Publish duration Correct answer
  • Memory address
  • Disk space
  • Thread count

Explanation: TimedPublisher measures the elapsed time of the publish.

2 Complete the timing call

Question
long start = System.____;
Answer
long start = System.nanoTime();

Explanation: System.nanoTime() gives a high-resolution time.

3 Match the performance elements

Term Meaning
nanoTime High-resolution clock
TimedPublisher Timing wrapper
delegate Wrapped publisher
decorator Wrapping pattern

All lessons in Expert