Atomic variables and non blocking synchronization in concurrent Java programming

  • 2020-04-01 03:49:01
  • OfStack

1. Non-blocking algorithm

Non-blocking algorithms are concurrent algorithms that can safely derive their threads, not through locking, but through low-level atomic hardware native forms such as comparison and exchange. Non-blocking algorithms are extremely difficult to design and implement, but they provide better throughput and better defense against survival problems such as deadlocks and priority reversals. Replace locks with the underlying atomized machine instructions, such as compare and swap (CAS,compare-and-swap).

Pessimistic technology

An exclusive lock is a pessimistic technique that assumes the worst (if left unlocked, other threads will destroy object state) and protects object state with a lock even if the worst does not happen.

Optimistic techniques

Update first, if a conflict occurs, give up the update and retry, otherwise the update succeeds.

4. The CAS operation

CAS has three operands, the memory value V, the old expected value A, and the new value B to be modified. If and only if the expected value A and memory value V are the same, change the memory value V to B, otherwise do nothing. The typical usage pattern of CAS is to first read A from V and calculate the new value B based on A, and then atomically change the value in V from A to B through CAS (as long as no thread changes the value of V to any other value during this period).

Listing 3. Code that illustrates the behavior (not the performance) of comparing and exchanging


public class SimulatedCAS {
     private int value;      public synchronized int getValue() { return value; }     public synchronized int compareAndSwap(int expectedValue, int newValue) {
         int oldValue = value;
         if (value == expectedValue)
             value = newValue;
         return oldValue;
     }
}

Listing 4. Implement the counter using compare and swap

public class CasCounter {
    private SimulatedCAS value;
    public int getValue() {
        return value.getValue();
    }
    public int increment() {
        int oldValue = value.getValue();
        while (value.compareAndSwap(oldValue, oldValue + 1) != oldValue)
            oldValue = value.getValue();
        return oldValue + 1;
    }
}

5. Atomic variables

Atomic variables support atomic update operations without lock protection, and the underlying implementation is CAS. There are 12 atomic variables, which can be divided into four groups: scalar class, updater class, array class, and composite variable class. The most common atomic variables are the scalar classes: AtomicInteger, AtomicLong, AtomicBoolean, and AtomicReference. CAS is supported for all types.

6. Performance comparison: locks versus atomic variables

Under the medium and low degree of competition, atomic variables can provide high scalability, and the performance of atomic variables is better than that of locks. But under the high intensity competition, the lock can avoid the competition more effectively, the performance of the lock will exceed the performance of the atomic variable. But in a more realistic scenario, the performance of atomic variables would exceed that of locks.


Related articles: