Final classes vs. `volatile` fields

1 day ago 2
ARTICLE AD BOX

One of the guarantees of Java's memory model is that return from a constructor of a final class - having only final fields - happens-before any assignment of the reference to the created object. In other words, the following code is thread safe:

class State { private final int a; private final int b; public State(int a, int b) { this.a = a; this.b = b; } public int sum() { return a + b; } } class Sum { private State state; public void setState(State state) { this.state = state; } public int sum() { return state.sum(); } } final Sum sum = new Sum(); sum.setState(new State(0, 0)); new Thread(() -> { int i = 0; while (true) { sum.setState(new State(i, -i)); i += 1; } }).start(); new Thread(() -> { while (true) { System.out.println(sum.sum()); //Will always print 0 } }).start();

If the fields of class State were not final, then Sum.state should be declared as volatile to achieve semantic guarantees (or use other synchronization mechanisms). However, volatile is not free; it prevents reordering by the CPU which can be visible in tight loops. I wonder if final class guarantees come with a similar cost.

I am implementing a mutable CharSequence which should be thread safe. In order to minimize the synchronization overhead while maintaining the required invariant for the state of several variables, I intend to extract the implementation to a separate, immutable class, and have my CharSequence delegate all the methods to a field of that class in a manner similar to the example above. This, in particular, includes charAt, which is very likely to be called in tight loops. I wonder if I will be able to see any difference between an immutable state class, and a mutable one assigned to a volatile field (lets restrict ourselves to ARM and x686)? The immutability is not free; for example, some of the fields of the State class serve an auxiliary statistic function with zero impact on correctness of charAt, and making them final will force the creation of a new State instance whenever they need to be updated.

I am interested in as little overhead as possible when using the state (delegating to it) - changes are frequent enough to throw a wrench into the implementation, but will most likely be outnumbered by at least an order of magnitude by reads and can be slower.

To answer the unevitable 'why don't you benchmark it?' question: I very much would like. However, writing synthetic benchmarks is an art requring good understanding of the whole process, and I face traditional challanges:

Micro benchmark executes the code in isolation, with C2 hotspot sure to kick in, which is not guaranteed in a real system;

I do not have real control of how my class will be used by others;

I am don't know how to make sure that I measure what I am actually interested in, that is what kind of unwanted optimizations could potentially the JVM make that could reduce the problem due to its minimized nature.

Therefore, advice on how to benchmark code would be also appreciated.

Read Entire Article