Java atomic operations and three problems

What is an atomic operation

http://www.infoq.com/cn/articles/atomic-operations-and-contention
computer operations is the most important constituent unit of an atomic operation. Here atoms with atomic physics says has nothing to do, but from the word atom, which is Greek "ἄτομος" (meaning not visible). Atomic operation is an operation can not be subdivided, or other processors in the system, no longer appears to be divided. In order to explain why the atomic operation is very important, consider two processors in much the same way to add a counter, translated into C language is counter ++, what will happen this time:

Instruction cycle A processor Two processors
0 reg = load(&counter);
1 reg = reg + 1; reg = load(&counter);
2 store(&counter, reg); reg = reg + 1;
3 store(&counter, reg);

In compiled code, such an operation is divided into: a read operation, the register is incremented and the last is a write operation (here represented by a C-like pseudo-code). These three steps are executed sequentially and independently (note that, for the x86, on a more micro level architecture of this sentence is correct, but the instruction set architecture level, which may be a three-step look "read - modify - write (read-modify-write)" instruction is completed: add [memory], value) . And since these operations are then divided into a plurality of instruction cycles to execute, so the processor reading a counter (and it is beginning to add a), before writing the result back gap, two processors is also possible to read it. Although the resulting two processors to increase the counter, but the final value of the counter is incremented by 1 only, wherein adding a "lost".

Atomic operations precisely to prevent this problem. If we use an atom of self-add operation (say a little more generic, atomic addition) rather than the conventional self-add operation, a processor executing instructions will ensure that the above three steps (read, add, write) like a command like completed, it becomes an atomic operation. When self-imposed operations, and other processor can not intervene.

What is CAS

Compare and swap Compare and Swap

CAS operation requires two input values, an old value (a desired value before the operation) and a new value, during operation of the old first comparison values are not changed, if the change does not occur, before switching to a new value, changes no exchange.
V (value required memory read / old value) == A (value to be compared) V = B (B intends to write a new value)

CAS cycle implemented using atomic operations

CAS operation is the use of the JVM CMPXCHG instructions provided by the processor implementation.

The basic idea is to achieve the spin cycle CAS CAS operation until it is successful, the following code implements counter method safeCount a CAS-based thread-safe and a non-thread-safe counter count.

package com.usoft;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

public class Counter {
    private AtomicInteger atomicI = new AtomicInteger(0);
    private int i = 0;

    public static void main(String[] args) {
        final Counter cas = new Counter();
        List<Thread> ts = new ArrayList<Thread>(600);
        long start = System.currentTimeMillis();
        for (int j = 0; j < 100; j++) {
            Thread t = new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10000; i++) {
                        cas.count();
                        cas.safeCount();
                    }
                }
            });
            ts.add(t);
        }

        for (Thread t : ts) {
            t.start();
        }
        // 等待所有线程执行完成
        for (Thread t : ts) {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        System.out.println(cas.i);
        System.out.println(cas.atomicI.get());
        System.out.println(System.currentTimeMillis() - start);

    }

    /**
     * 使用CAS实现线程安全计数器
     */
    private void safeCount() {
        for (;;) {
            int i = atomicI.get();
            boolean suc = atomicI.compareAndSet(i, ++i);
            if (suc) {
                break;
            }
        }
    }

    /**
     * 非线程安全计数器
     */
    private void count() {
        i++;
    }
}

From the start Java1.5 JDK concurrent package provides classes to support atomic operations, such as An AtomicBoolean is (updated atomically boolean value), of AtomicInteger (atomically updated int value), AtomicLong (long updated atomically values), these atoms packaging also provides methods useful tools, such as to the current value of the atomic increment and decrement 1 1.

Although very efficient solution CAS atomic operations, but CAS is still three problems. ABA problem, long cycle time and can guarantee a large overhead shared variable atomic operations.

1, ABA problem:

Because the CAS needs to check the value at the time of operation under values are not changed, if not changed is updated, but if a value is A, became a B, he is a A, you will find that when using CAS inspection its value has not changed, but actually changed. Solutions ABA problem is to use a version number. The version number is added in front of variables, each variable is updated when the version number plus one, then the A-B-A becomes 1A-2B-3A.

From the beginning of the JDK atomic Java1.5 package provides a class AtomicStampedReference to address the ABA problem. The method of action of this class is compareAndSet checks the current reference is equal to the expected reference and the current mark is equal to the expected flag, if all equal Atomically the reference value and the flag is set to the given updated value.

public boolean compareAndSet

(
V expectedReference, // the expected reference

V newReference, cited after the update //

int expectedStamp, // is expected to sign

newStamp int
) mark after the // Update

2, long cycle time overhead large:
Spin CAS if not successful for a long time, will bring a very large execution overhead CPU. If the JVM can support pause instructions provided by the processor so there will be some efficiency improvement, pause command serves two purposes, first it may delay pipelined execution of instructions (de-pipeline), the CPU does not consume too many resources for implementation, delay time implementation dependent, the delay time on the number of processors is zero. It can avoid a second exit loop when the order due to memory conflicts (memory order violation) caused by CPU pipeline is cleared (CPU pipeline flush), in order to improve the efficiency of the CPU.

3, atomic operations can only guarantee a shared variable:
when performing operations on a shared variable, we can use the CAS cycle approach to ensure an atomic operation, but when multiple shared variables operating cycle CAS can not guarantee atomic operations sex, this time we can use locks, or have a tricky way, it is to merge multiple shared variables into a shared variable to operate. For example there are two shared variables i = 2, j = a, merge at ij = 2a, and to operate with CAS ij. From the beginning Java1.5 JDK classes AtomicReference provided to ensure the reference atom between objects, you can put an object in the plurality of variables on the CAS operation is performed.

A lock mechanism to achieve atomic operations

Lock mechanism ensures that the memory area of the thread can only obtain a lock operation lock. JVM internals to a variety of locking mechanism, biased lock, mutex lock and lightweight, the cycle is interesting that in addition to CAS biased lock, lock JVM implementation of methods are used, when a thread wants to enter the synchronized block use of recycled CAS way to get a lock when it exits the synchronized block when using CAS cycle to release the lock. Details can be found in the article Java SE1.6 Synchronized.

http://www.infoq.com/cn/articles/java-se-16-synchronized

Published 107 original articles · won praise 14 · views 40000 +

Guess you like

Origin blog.csdn.net/belongtocode/article/details/103343800