Adding @atomic operations to Java

Overview

How might atomic operations work in Java, and is there a current alternative in OpenJDK/Hotspot it could translate to.

Feedback

In my previous article on Making operations on volatile fields atomic. it was pointed out a few times that “fixing” previous behaviour is unlikely to go ahead regardless of good intentions.

 
An alternative to this is to add an @atomic annotation.  This has the advantage of only applying to new code and not risk breaking old code.

Note: The use of a lower case name is intentional as it *doesn’t* follow current coding conventions.

Atomic operations

Any field listed with an @atomic would make the whole expression atomic.  Variables which are non-volatile and non-atomic could be read at the start, or set after the completion of the expression.  The expression itself may require locking on some platforms, CAS operations or TSX depending on the CPU technology.

If fields are only read, or only one is written too, this would be the same as volatile.

Atomic Boolean

Currently the AtomicBoolean uses 4 bytes, plus an object header, with possible padding (as well as a reference)  If the field was inlined it could look like this

 @atomic boolean flag;
// toggle the flag.
this.flag = !this.flag;

But how would it work?  Not all platforms support 1 byte atomic operations e.g. Unsafe does have a 1 byte CAS operations.  This can be done with masking.

 // possible replacement.
while(true) {
     int num = Unsafe.getUnsafe().getVolatileInt(this, FLAG_OFFSET & ~3); // word align the access.
     int value ^= 1 << ~(0xFF << (FLAG_OFFSET & 3) * 8) ;
     if (Unsafe.getUnsafe().compareAndSwapInt(this, FLAG_OFFSET & ~3, num, value))
           break;
}

Atomic Double

A type which is not supported is AtomicDouble, but this is a variation on AtomicLong.  Consider this example.

 @atomic double a = 1;
volatile double b = 2;

a += b;

How might it be implemented today?

while(true) {
    double _b = Unsafe.getUnsafe().getVolatileDouble(this, B_OFFSET);
    double _a = Unsafe.getUnsafe().getVolatileDouble(this, A_OFFSET);
    long aAsLong = Double.doubleToRawLongBits(_a);
    double _sum = _a + _b;
    long sumAsLong = Double.doubleToRawLongBits(_a);
    if (Unsafe.getUnsafe().compareAndSwapLong(this, A_OFFSET, aAsLong, sumAsLong))
        break;
}

Two Atomic Fields

Using Intel TSX, you can wrap a hardware transaction around a number of fields, but what if you don't have TSX, could it still be done, without resorting to a lock.

 @atomic int a = 1, b = 2;

a += b * (b % 2 == 0 ? 2 : 1);

This can still be done with the CAS if the fields are together.  There is a CAS2 operation planned to be able to check two 64-bit values.  For now, this example will use two 4-byte values.

assert A_OFFSET + 4 == B_OFFSET;
while(true) {
    long _ab = Unsafe.getUnsafe().getVolatileLong(this, A_OFFSET);
    int _a = getLowerInt(_ab);
    int _b = getHigherInt(_ab);
    int _sum = _a + _b * (_b % 2 == 0 ? 2 : 1);
    int _sum_ab = setLowerIntFor(_ab, _sum);
    if (Unsafe.getUnsafe().compareAndSwapLong(this, A_OFFSET, _ab, _sum_ab))
        break;
}

Note: This operation can handle the change of either a, or b or both in an atomic way.

AtomicReferences

A common use case operations on immutable objects such as BigDecimal.

 @atomic BigDecimal a;
BigDecimal b;

a = a.add(b);

could be implemented this way on systems with CompressedOops or 32-bit JVMs.

BigDecimal _b = this.b;
while(true) {
    BigDecimal _a = (BigDecimal) Unsafe.getUnsafe().getVolatileObject(this, A_OFFSET);
    BigDecimal _sum = _a.add(_b);
    if (Unsafe.getUnsafe().compareAndSwapLong(this, A_OFFSET, _a, _sum))
        break;
}

More complex examples

There will always be examples which are too complex for your platform.  They might be fine on a System with TSX or HotSpot supported systems, however you need a fall back.

@atomic long a, b, c, d;

a = (b = (c = d + 4) +  5 ) + 6;

This is not support currently as it set multiple long values in one expression. However, a fall back could be to use the existing lock.

 synchronized(this) {
    a = (b = (c = d + 4) +  5 ) + 6;
}

Conclusion

By adding an annotation, we could add atomic operations to regular fields, without the need to change the syntax.  This would be a natural extension to the language without breaking backward comparability.

Reference: Adding @atomic operations to Java from our JCG partner Peter Lawrey at the Vanilla Java blog.
Related Whitepaper:

Bulletproof Java Code: A Practical Strategy for Developing Functional, Reliable, and Secure Java Code

Use Java? If you do, you know that Java software can be used to drive application logic of Web services or Web applications. Perhaps you use it for desktop applications? Or, embedded devices? Whatever your use of Java code, functional errors are the enemy!

To combat this enemy, your team might already perform functional testing. Even so, you're taking significant risks if you have not yet implemented a comprehensive team-wide quality management strategy. Such a strategy alleviates reliability, security, and performance problems to ensure that your code is free of functionality errors.Read this article to learn about this simple four-step strategy that is proven to make Java code more reliable, more secure, and easier to maintain.

Get it Now!  

Leave a Reply


4 × four =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.

Sign up for our Newsletter

20,709 insiders are already enjoying weekly updates and complimentary whitepapers! Join them now to gain exclusive access to the latest news in the Java world, as well as insights about Android, Scala, Groovy and other related technologies.

As an extra bonus, by joining you will get our brand new e-books, published by Java Code Geeks and their JCG partners for your reading pleasure! Enter your info and stay on top of things,

  • Fresh trends
  • Cases and examples
  • Research and insights
  • Two complimentary e-books