Concurrent programming - Hardware blessing of CAS operations fast enough it?

Talk is cheap

CAS (Compare And Swap), i.e., compare and swap. Is used to solve the multi-thread lock mechanism caused loss of performance of the parallel case, CAS operation includes three operands - a memory location (V), is expected to original value (A) and the new value (B). If the memory location of the original value matches the expected value, then the processor will automatically update the location value to the new value. Otherwise, the processor does nothing. Regardless of the value of V is equal to the position A, it is returned to the original value V.

CAS means "I think it should be the value of V A, and if so, then I will update the value of V B, V or not the change and share value is the number of actual"

Show you my code

In single-threaded environment are no lock, for locking and cas ten groups of 500 million accumulate operations, and then print out the average time.

 /**
 * cas对比加锁测试
 *
 * @author Jann Lee
 * @date 2019-11-21 0:12
 **/
public class CasTest {

    @Test
    public void test() {
        long times = 500_000_000;
        // 记录耗时
        List<Long> elapsedTime4NoLock = new ArrayList<>(10);
        List<Long> elapsedTime4Synchronized = new ArrayList<>(10);
        List<Long> elapsedTime4ReentrantLock = new ArrayList<>(10);
        List<Long> elapsedTime4Cas = new ArrayList<>(10);

        // 进行10组试验
        for (int j = 0; j < 10; j++) {
            // 无锁
            long startTime = System.currentTimeMillis();
            for (long i = 0; i < times; i++) {
            }
            long endTime = System.currentTimeMillis();
            elapsedTime4NoLock.add(endTime - startTime);

            // synchronized 关键字(隐式锁)
            startTime = endTime;
            for (long i = 0; i < times; ) {
                i = addWithSynchronized(i);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Synchronized.add(endTime - startTime);

            // ReentrantLock 显式锁
            startTime = endTime;
            ReentrantLock lock = new ReentrantLock();
            for (long i = 0; i < times; ) {
                i = addWithReentrantLock(i, lock);
            }
            endTime = System.currentTimeMillis();
            elapsedTime4ReentrantLock.add(endTime - startTime);

            // cas(AtomicLong底层是用cas实现)
            startTime = endTime;
            AtomicLong atomicLong = new AtomicLong();
            while (atomicLong.getAndIncrement() < times) {
            }
            endTime = System.currentTimeMillis();
            elapsedTime4Cas.add(endTime - startTime);
        }

        System.out.println("无锁计算耗时: " + average(elapsedTime4NoLock) + "ms");
        System.out.println("synchronized计算耗时: " + average(elapsedTime4Synchronized) + "ms");
        System.out.println("ReentrantLock计算耗时: " + average(elapsedTime4ReentrantLock) + "ms");
        System.out.println("cas计算耗时: " + average(elapsedTime4Cas) + "ms");

    }

    /**
     * synchronized加锁
     */
    private synchronized long addWithSynchronized(long i) {
        i = i + 1;
        return i;
    }

    /**
     * ReentrantLock加锁
     */
    private long addWithReentrantLock(long i, Lock lock) {
        lock.lock();
        i = i + 1;
        lock.unlock();
        return i;
    }

    /**
     * 计算平均耗时
     */
    private double average(Collection<Long> collection) {
        return collection.stream().mapToLong(i -> i).average().orElse(0);
    }
}

From the cases we might see in a single-threaded environment scene cas performance is higher than the operation of the lock-related. Of course, in the case of more intense competition performance may decline, because to constantly retry and rollback or abort the operation , a disadvantage of this is where the CAS, because these retry, rollback and other operations usually developers to realise.

CAS implementation is not a simple code-level control, but requires hardware support, significant performance difference so executed between different architectures. But a very useful rule of thumb is: on most processors, spending on non-competitive lock acquisition and release of "quick code path", and is about twice the cost of the CAS.

Why CAS so good

Hardware blessing , most modern processors achieve CompareAndSwap from the hardware level through a series of instructions (compare and swap) synchronization primitives, thereby enabling the operating system and the JVM can use these instructions to achieve locking and concurrent data structures. We can simply think, CAS is to compare and exchange synthesis is an atomic operation .

JVM support for the CAS , because the Java program to run on the JVM, so deal with handling different hardware architecture is required to realize JVM. On the hardware does not support CAS operation, jvm will be used to implement a spin lock.

The ABA problem CAS

cas operation allows us to reduce the performance loss caused by the lock, but also brought us new troubles -ABA problem.

During execution CAS value read operation in thread A of x, x thread B executed twice for modifying the value of x from 100 into 200, and then back to 100 from 200; CAS operation then execution thread A x did not find the change occurred, successfully modified the value of x. Since the value of x 100 -> 200-> 100, the so called ABA reasons.

Magic goes Road ridge, ABA solve problems most common way is to add data "version", while changing the version number every time when you can modify the data.

Q&A

In the case of more intense competition, CAS should be rolled back, the retry and other operations in order to get the correct result, then CAS must be higher than the performance it locked?

Guess you like

Origin www.cnblogs.com/liqiangchn/p/11902198.html