Performance layer
- Java course
- Expert
- Lesson 44/46
- 6 min
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
@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
@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
long start = System.____;
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 |