Abstract: Java 9 is more strict about what system internal classes we can use. So how can we use @Contended in Java 9? This article shows you how.
Welcome to the 249th edition of The Java(tm) Specialists' Newsletter, sent to you from the Island of Crete. To the left of where I'm sitting, Mr Kostas' grapes are ripening in the sun, ready to be turned into Cretan village wine and tzikoudia. He acted in "Zorba the Greek" as a little boy. Now he is a grandfather in his 70s. If you've never seen "Zorba the Greek" [ISBN B007QU37GQ] , you owe it to yourself to watch this classic. If anything, you will see how my neighbourhood looked a long time ago :-)
javaspecialists.teachable.com: Please visit our new self-study course catalog to see how you can upskill your Java knowledge.
A few months ago, I was trying to figure out how to use
@Contended
in Java 9. I was thwarted. Then, whilst preparing for
this
month's webinar, I finally managed. Since it is highly
likely that I will forget how, I thought it would be useful
to write it down as a newsletter. That way, some time in the
future, when I "google" "@Contended Java 9" I will hopefully
find my article :-)
A little bit of background re @Contended
.
It is an annotation added in Java 8 to pad fields.
The reason why this can be helpful is to avoid false sharing
in cache lines. @Contended
is a
sun.misc
annotation, which
means that we should ideally not use it in our code. There
are techniques for padding without resorting to
@Contended
,
using some weird tricks to guarantee that the padding is in
the correct place. See Blackhole class in JMH.
This newsletter is not going to answer the question of "why?"
we would want to make some fields @Contended
, nor the
questions "which?" and "when?". I'm assuming you know this
already. If you don't, I'd suggest you try Extreme Java - Concurrency
Performance by Heinz Kabutz, Mechanical
Sympathy Blog by Martin Thompson and Psychosomatic,
Lobotomy, Saw Blog by Nitsan Wakart. The only
question I'm going to answer is "how?" do you do that in Java
9?
In Java 8, we could mark a field as @Contended
simply like
so:
public class Cell { @sun.misc.Contended private volatile long value; }
When we compile our class in Java 8, we saw this warning, but it compiled without error:
heinz$ javac Cell.java Cell.java:2: warning: Contended is internal proprietary API and may be removed in a future release @sun.misc.Contended ^ 1 warning
By default, since our class is not in the bootclasspath, this annotation would have no effect. Here is some of the output when we run jol internals on our Cell:
Cell object internals: OFFSET SIZE TYPE DESCRIPTION 0 4 (object header) 4 4 (object header) 8 4 (object header) 12 4 (alignment/padding gap) 16 8 long Cell.value Instance size: 24 bytes Space losses: 4 bytes internal + 0 bytes external = 4 bytes total
However, we can make the @Contended annotation take effect when we launch jol with the -XX:-RestrictContended JVM flag.
Cell object internals: OFFSET SIZE TYPE DESCRIPTION 0 4 (object header) 4 4 (object header) 8 4 (object header) 12 132 (alignment/padding gap) 144 8 long Cell.value 152 128 (loss due to the next object alignment) Instance size: 280 bytes Space losses: 132 bytes internal + 128 bytes external = 260 bytes total
As you can see, objects of type Cell use far more memory when a field is @Contended.
Here are some classes that use @Contended in Java 8:
Java 9 tries to stop us from shooting ourselves in the foot.
Classes like sun.misc.Contended
, sun.misc.Unsafe
and
sun.misc.Cleaner
have been marched out of publicly available
packages and into jdk.internal.**
, where no non-Oracle
programmer may enter. They relented a bit by leaving
sun.misc.Unsafe
for us to play with, with the
promise that it
will be gone in Java 10, once we've moved all our code over
to VarHandle.
Thus, if you change the package to jdk.internal.**
, our class
will no longer compile:
public class Cell { @jdk.internal.vm.annotation.Contended private volatile long value; }
And now javac has the audacity to tell us:
heinz$ javac Cell.java Cell.java:2: error: package jdk.internal.vm.annotation is not visible @jdk.internal.vm.annotation.Contended ^ (package jdk.internal.vm.annotation is declared in module java.base, which does not export it to the unnamed module) 1 error
The java and javac commands have some additional flags that
allow us access to restricted packages. Since we have not
defined a module for our Cell class, it is in the "unnamed"
module. We can export it to our "unnamed" module with the
additional javac flag --add-exports
java.base/jdk.internal.vm.annotation=ALL-UNNAMED
Of course, if your class is in a module, you'll have to
specify that instead of ALL-UNNAMED.
heinz$ javac --add-exports \ java.base/jdk.internal.vm.annotation=ALL-UNNAMED Cell.java
No error. No warning. Bliss.
Sometimes we might want to do some deep reflection on members of other modules. We can open up other modules with --add-opens, giving us access to private fields, methods, etc. The --add-opens removes more barriers than --add-exports. In fact, --add-opens implies --add-exports. It would not make sense to allow --add-opens with the javac command, as the compiler should anyway not allow us to access the private members of other classes. This is why javac only allows --add-exports (allowing us to access public members of non-exported classes).
Looking back at the various versions of Java, I think migrating to Java 9 will give us the most amount of work for the least benefit. It is scary how many companies are still stuck on Java 6 or 7. Even though the 6->7 and 7->8 migrations were relatively painless, it is still taking companies a very long time to move. However, we don't have a choice. We have to move forward. Eventually your version of Java will not be supported anymore. Such is life :-)
Kind regards from Crete
Heinz
P.S. I also spoke about @Contended in this month's "Heinz's Happy Hour". You can find all our recordings here.
We are always happy to receive comments from our readers. Feel free to send me a comment via email or discuss the newsletter in our JavaSpecialists Slack Channel (Get an invite here)
We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.