Home of The JavaSpecialists' Newsletter

249@Contended @since 9

Posted: 2017-08-23Category: ConcurrencyJava Version: 9-eaDr. Heinz M. Kabutz
 

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", you owe it to yourself to watch this classic. If anything, you will see how my neighbourhood looked a long time ago :-)

Dr Heinz's Extreme Java Courses: We offer our courses as In-house and Self-Study options. In-house is best for large teams of Java experts. Self-study is suitable for individual programmers w ho want to advance their careers. If you have any questions, please simply send me an email or fill in our enquiry form :-)

@Contended @since 9

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:

  • Thread (for ThreadLocalRandom fields)
  • ConcurrentHashMap
  • LongAdder and LongAccumulator (in their superclass Striped64)
  • Exchanger (which I've never used)
  • ForkJoinPool

Enough Already, What About Java 9?

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.

--add-exports vs --add-opens

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.

 

Related Articles

Browse the Newsletter Archive

About the Author

demo

Java Champion, author of the Javaspecialists Newsletter, conference speaking regular... About Heinz

Java Training

We deliver relevant courses, by top Java developers to produce more resourceful and efficient programmers within their organisations.

Java Consulting

Nobody ever wants to call a Java performance consultant, but with first-hand experience repairing and improving commercial Java applications - JavaSpecialists are a good place to start...

Threading Emergency?

If your system is down, we will review it for 15 minutes and give you our findings for just 1 € without any obligation.