Language selector

Are you ready for Valhalla?

Many features and changes we see coming live in new Java version (if not most of them) are developed under so-called umbrella projects. We frequently see syntax improvements from project Amber, project Jigsaw is about bringing modules, project Loom (surprise, surprise) is about new threads, project Panama roughly speaking is about using native stuff safely and efficiently, and among the most known ones, project Valhalla starts to become a thing, thanks to JEP-390 being included in Java 16.

From my point of view (and you don’t have to agree with me), JEP-390 is similar in its nature to JEP-396, which I described in the previous installment. What makes is totally different though, is timing.

As we know, JPMS (Java Platform Module System), consisting of many JEPs and JSRs, saw the daylight officially with Java 9, being postponed for a few years. When we saw it, it was also accompanied by the illegal access warnings too, only we got a combo: actual change and actual warning at the same time, in the very same release. Of course, we witness now the warning (and violations of OOP) changing in Java 16 and (most probably) Java 17, but there was no official warning emitted, neither by javac, nor by JVM, in any release before.

Compared to that, project Valhalla reaches GA differently. We see some warnings first, giving us chance and time to prepare for the core Valhalla’s changes going live. Project Valhalla (and this is a gross oversimplification, my friends) is about allowing us creating value-based objects, i.e. objects which in a way are like primitive types we have in Java. To give you an example, when we have an array of, let’s say, one million objects packed into an array, do we really need all of them to have their unique header, if all of them have exactly the same header, and we don’t use a single object for synchronization? Maybe these objects could be more int-ish in their nature then? So we give up identity of these objects (which we don’t use anyway) to favour performance? That’s what more or less about it: about giving us opportunity to create objects where we care only about their value, hence value-based.

It turns out that there might be quite a few classes that should be used only for the value stored inside their objects and that they should be more like primitive pieces of data, despite not being defined as one of the primitive data types.

There’s a nice description of the expected properties of a value-based class, I really suggest reading it, as the definition changed slightly over recent releases.

What’s a value-based class actually?

[Update: I also covered this in the part one of Java 16. What’s new and noteworthy.]

Currently, these are all classes annotated with jdk.internal.@ValueBased. Examples are:

  • java.lang.{Byte, Short, Integer, Long, Float, Double, Boolean, Character}
  • java.util.{Optional, OptionalDouble, ...}
  • java.time.{Instant, ZonedDateTime, Duration, ...}
  • implementations of results returned by methods like List.of(), List.copyOf(), Set.of(), ..., Map.entry()

If we simplify things again, we could say about such classes, that their objects should be created using factory methods (not constructors), and they give up their identity (being able to be compared using == or used in synchronized clause), to rely solely on equality (using equals()) in Java. Thanks to all of that and being immutable, the objects/instances can be freely replaced one by another, something similar to what we have with -XX:+UseStringDeduplication.

Let’s check some real examples to see what these changes are all about and how to detect violations during compilation and during runtime.

All constructors are @Deprecated(forRemoval = true) now

Not that using a constructor for mentioned classes was easy or a good idea anytime in the past, but now if we try to call one directly in our code, we can not only see a warning in an IDE (like a red like striking through), but also a compiler warning:

warning: [removal] Long(long) in Long has been deprecated and marked for removal
private final static Long aLong = new Long(42);
                                  ^

Solution is quite simple: stop calling the constructors, go for direct calls of factory methods, e.g. Long.valueOf(42L), Duration.ofSeconds(15) or autoboxing when appropriate.

Synchronization attempts yield new synchronization warning

Whenever we try in our code to synchronize on an object of value-based class, the compiler will warn us using a new warning type, the synchronization warning:

warning: [synchronization] attempt to synchronize on an instance of a value-based class
    synchronized (aLong) {
    ^

This one is more tricky, because if your build tools don’t happen to be aware of this new type of warning, you might not see this warning at all. E.g. using Maven compiler plugin in version 3.8.1, even when directly enabling all compiler warnings (or just <compilerArg>-Xlint:synchronization</compilerArg>), this very warning cannot be seen, because using:

  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.8.1</version>
    <configuration>
      <compilerArgs>
        <!--<compilerArg>-Xlint:synchronization</compilerArg>-->
        <compilerArg>-Xlint:all</compilerArg>
      </compilerArgs>
    </configuration>
  </plugin>

results only with the previous warning (about using constructor):

[WARNING] (...)ValueBasedClasses.java:[28,39] Long(long) in java.lang.Long has been deprecated and marked for removal
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------

Please, be aware of that. Luckily for us, Intellij IDEA marks this okay (thankfully this warning doesn’t require indexing, it seems ;-) ).

Analysing 3rd party artifacts

It might be you don’t compile the sources yourself, but instead you’re using some JARs provided by or fetched from 3rd party / external vendor. Fear not, then just use jdeprscan and Bob’s your uncle!

$ jdeprscan goodies/target/goodies-1.0-SNAPSHOT.jar 
Jar file goodies/target/goodies-1.0-SNAPSHOT.jar:
class ValueBasedClasses uses deprecated method java/lang/Long::<init>(J)V (forRemoval=true)

Unfortunately, nothing seems to detect weird calls like

Long.class.getDeclaredConstructors()[0].newInstance("42");

but maybe there should be a sane limit in warnings ;-)

Runtime detection of synchronized

Checking for synchronized(valueObject) can also be performed during runtime, which is especially useful for 3rd party code (as it’s not picked up by jdeprscan). To enable it, your java parameters should contain either:

java -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=1

or

java -XX:+UnlockDiagnosticVMOptions -XX:DiagnoseSyncOnValueBasedClasses=2

The difference is in the way the JVM will react when synchronization on a value object is detected. DiagnoseSyncOnValueBasedClasses=1 results in your program instantly going belly up with message:

#  Internal Error (synchronizer.cpp:416), pid=29406, tid=29407
#  fatal error: Synchronizing on object 0x000000062f2a7bb8 of klass java.lang.Long at ValueBasedClasses.main(ValueBasedClasses.java:32)

whereas using DiagnoseSyncOnValueBasedClasses=2 is not fatal (i.e. the program will keep working) and makes each such attempt log a message like this:

[0,076s][info][valuebasedclasses] Synchronizing on object 0x000000062f2a7818 of klass java.lang.Long
[0,076s][info][valuebasedclasses] 	at ValueBasedClasses.main(ValueBasedClasses.java:32)
[0,076s][info][valuebasedclasses] 	- locked <0x000000062f2a7818> (a java.lang.Long)

What to do if I see any of these warnings?

Happy Viking

First I’d check if you have the warnings enabled and reported by your build tool and runtime.

Then it’s quite simple: stop using constructor and stop using value objects in synchronized block, use another object as a monitor, maybe even Object lock = new Object();

There’s no switch (or at least I’m not aware of it) that would “silence” such warnings in the future, like equivalent of --illegal-access=permit. And even if there was such a switch, I wouldn’t recommend using it.

Because if your code keeps using value-based classes in the way causing such warnings, you won’t be able to enter Valhalla for eternal glory!

Language selector