Interface AtomicBuffer

  • All Superinterfaces:
    java.lang.Comparable<DirectBuffer>, DirectBuffer, MutableDirectBuffer
    All Known Implementing Classes:
    UnsafeBuffer

    public interface AtomicBuffer
    extends MutableDirectBuffer
    Abstraction over a range of buffer types that allows type to be accessed with various memory ordering semantics.

    Before Java 9, there was no naming standard for stores with release semantics. On the AtomicLong there was the AtomicLong.lazySet(long). Because there was no standard, the AtomicBuffer has methods like putLongOrdered(int, long). With Java 9, the 'release' name has been introduced. The AtomicBuffer also has methods with release methods which are identical to the ordered methods. All the methods with 'ordered' name will call the equivalent method with release name. This introduces a small performance penalty for the older methods and this should encourage users to switch to the newer methods.

    In most cases you want to match the mutating method with the reading method:

    1. a putIntVolatile(int, int) with a getIntVolatile(int).
    2. a putIntRelease(int, int) with a getIntAcquire(int).
    3. a putIntOpaque(int, int) with a getIntOpaque(int).
    4. a MutableDirectBuffer.putInt(int, int) with an DirectBuffer.getInt(int).
    If the methods aren't matched then chances are there either is a data race or race condition due to too few constraints, or suboptimal performance due to too many constraints. Also, when there is a mismatch it makes understanding code harder as well because it isn't clear how much synchronization is actually needed.

    For a read or write to be atomic, the fields needs to be naturally aligned. E.g. an int should be 4 bytes aligned and a long should be 8 bytes aligned. Some ISA's are more lenient like the X86, although there can be severe performance penalties. But other ISA's are less forgiving.

    • Field Detail

      • ALIGNMENT

        static final int ALIGNMENT
        Buffer alignment in bytes to ensure atomic word accesses.
        See Also:
        Constant Field Values
      • STRICT_ALIGNMENT_CHECKS_PROP_NAME

        static final java.lang.String STRICT_ALIGNMENT_CHECKS_PROP_NAME
        Name of the system property that specify if the alignment checks for atomic operations are strict. If the checks are strict then the verifyAlignment() method will throw an exception if the underlying buffer is a byte[].
        See Also:
        Constant Field Values
      • STRICT_ALIGNMENT_CHECKS

        static final boolean STRICT_ALIGNMENT_CHECKS
        Should alignment checks for atomic operations be done or not. The value is platform-dependent:
        See Also:
        STRICT_ALIGNMENT_CHECKS_PROP_NAME
    • Method Detail

      • verifyAlignment

        void verifyAlignment()
        Verify that the underlying buffer is correctly aligned to prevent word tearing, other ordering issues and the JVM crashes. In particular this method verifies that the starting offset of the underlying buffer is properly aligned. However, the actual atomic call must ensure that the index is properly aligned, i.e. it must be aligned to the size of the operand. For example a call to any of the following methods putIntRelease(int, int), putIntVolatile(int, int), addIntRelease(int, int) (int, int)}, getIntVolatile(int), getAndAddInt(int, int) or getAndSetInt(int, int), must have the index aligned by four bytes (e.g. 0, 4, 8, 12, 60 etc.).

        Users are encouraged to call this method after constructing the AtomicBuffer instance in order to ensure that the underlying buffer supports atomic access to long values.

        Agrona provides an agent (org.agrona.agent.BufferAlignmentAgent) that checks the alignment of indexes for all operations at runtime. The agent throws an exception if the unaligned access is detected.

        Note: on some platforms unaligned atomic access can lead to the JVM crashes, e.g.:

         
         # Java VM: OpenJDK 64-Bit Server VM (25.352-b08 mixed mode bsd-aarch64 compressed oops)
         #
         # siginfo: si_signo: 10 (SIGBUS), si_code: 1 (BUS_ADRALN)
         
         
        Throws:
        java.lang.IllegalStateException - if the starting offset into the buffer is not properly aligned.
        See Also:
        ALIGNMENT
      • getLongVolatile

        long getLongVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • getLongAcquire

        long getLongAcquire​(int index)
        Atomically get the value at a given index with acquire semantics.
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
        Since:
        2.1.0
      • putLongVolatile

        void putLongVolatile​(int index,
                             long value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • putLongOrdered

        void putLongOrdered​(int index,
                            long value)
        Atomically put a value to a given index with ordered store semantics.

        Instead of using this method, use putLongRelease(int, long) instead. They are identical and the putLongRelease is the preferred version.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • putLongRelease

        void putLongRelease​(int index,
                            long value)
        Atomically put a value to a given index with release semantics.
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Since:
        2.1.0
      • addLongOrdered

        long addLongOrdered​(int index,
                            long increment)
        Atomically adds a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Instead of using this method, use addLongRelease(int, long) instead. They are identical but the addLongRelease is the preferred version.

        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • putLongOpaque

        void putLongOpaque​(int index,
                           long value)
        Atomically put a value to a given index with opaque semantics.
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Since:
        2.1.0
      • getLongOpaque

        long getLongOpaque​(int index)
        Atomically get a value to a given index with opaque semantics.
        Parameters:
        index - in bytes for where to put.
        Returns:
        the value for at a given index.
        Since:
        2.1.0
      • addLongOpaque

        long addLongOpaque​(int index,
                           long increment)
        Adds a value to a given index with opaque semantics. The read and write will be atomic, but the combination is not atomic. So don't use this method concurrently because you can run into lost updates due to a race-condition.
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
        Since:
        2.1.0
      • addLongRelease

        long addLongRelease​(int index,
                            long increment)
        Atomically adds a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
        Since:
        2.1.0
      • compareAndSetLong

        boolean compareAndSetLong​(int index,
                                  long expectedValue,
                                  long updateValue)
        Atomic compare and set of a long given an expected value.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        set successful or not.
      • compareAndExchangeLong

        long compareAndExchangeLong​(int index,
                                    long expectedValue,
                                    long updateValue)
        Atomic compare and exchange of a long given an expected value.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        the old value no matter if the expected value was found.
        Since:
        2.1.0
      • getAndSetLong

        long getAndSetLong​(int index,
                           long value)
        Atomically exchange a value at a location returning the previous contents.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Returns:
        previous value at the index.
      • getAndAddLong

        long getAndAddLong​(int index,
                           long delta)
        Atomically add a delta to a value at a location returning the previous contents. To decrement a negative delta can be provided.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        delta - to be added to the value at the index.
        Returns:
        previous value.
      • getIntVolatile

        int getIntVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putIntVolatile

        void putIntVolatile​(int index,
                            int value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getIntAcquire

        int getIntAcquire​(int index)
        Atomically get the value at a given index with acquire semantics.
        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
        Since:
        2.1.0
      • putIntOrdered

        void putIntOrdered​(int index,
                           int value)
        Atomically put a value to a given index with ordered semantics.

        Instead of using this method, use putIntRelease(int, int) instead. They are identical but the putIntRelease is the preferred version.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • putIntRelease

        void putIntRelease​(int index,
                           int value)
        Atomically put a value to a given index with release semantics.
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Since:
        2.1.0
      • addIntOrdered

        int addIntOrdered​(int index,
                          int increment)
        Atomically add a value to a given index with ordered store semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Instead of using this method, use addIntRelease(int, int) instead. They are identical but the addIntRelease is the preferred version.

        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
      • addIntRelease

        int addIntRelease​(int index,
                          int increment)
        Atomically add a value to a given index with release semantics. Use a negative increment to decrement.

        The load has no ordering semantics. The store has release semantics.

        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
        Since:
        2.1.0
      • putIntOpaque

        void putIntOpaque​(int index,
                          int value)
        Atomically put a value to a given index with opaque semantics.
        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Since:
        2.1.0
      • getIntOpaque

        int getIntOpaque​(int index)
        Atomically get a value to a given index with opaque semantics.
        Parameters:
        index - in bytes for where to put.
        Returns:
        the value for at a given index.
        Since:
        2.1.0
      • addIntOpaque

        int addIntOpaque​(int index,
                         int increment)
        Adds a value to a given index with opaque semantics. The read and write will be atomic, but the combination is not atomic. So don't use this method concurrently because you can run into lost updates due to a race-condition.
        Parameters:
        index - in bytes for where to put.
        increment - by which the value at the index will be adjusted.
        Returns:
        the previous value at the index.
        Since:
        2.1.0
      • compareAndSetInt

        boolean compareAndSetInt​(int index,
                                 int expectedValue,
                                 int updateValue)
        Atomic compare and set of an int given an expected value.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        successful or not.
      • compareAndExchangeInt

        int compareAndExchangeInt​(int index,
                                  int expectedValue,
                                  int updateValue)
        Atomic compare and exchange of a int given an expected value.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        expectedValue - at to be compared.
        updateValue - to be exchanged.
        Returns:
        the old value no matter if the expected value was found.
        Since:
        2.1.0
      • getAndSetInt

        int getAndSetInt​(int index,
                         int value)
        Atomically exchange a value at a location returning the previous contents.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
        Returns:
        previous value.
      • getAndAddInt

        int getAndAddInt​(int index,
                         int delta)
        Atomically add a delta to a value at a location returning the previous contents. To decrement a negative delta can be provided.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        delta - to be added to the value at the index.
        Returns:
        previous value.
      • getShortVolatile

        short getShortVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putShortVolatile

        void putShortVolatile​(int index,
                              short value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getCharVolatile

        char getCharVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putCharVolatile

        void putCharVolatile​(int index,
                             char value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.
      • getByteVolatile

        byte getByteVolatile​(int index)
        Atomically get the value at a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes from which to get.
        Returns:
        the value for at a given index.
      • putByteVolatile

        void putByteVolatile​(int index,
                             byte value)
        Atomically put a value to a given index with volatile semantics.

        This call has sequential-consistent semantics.

        Parameters:
        index - in bytes for where to put.
        value - for at a given index.