zoukankan      html  css  js  c++  java
  • 017 无锁与CAS

    一 . 概述

    我们知道加锁会对多线程的并发有影响,那么我们是否有无锁的方式保证线程的安全性呢?有的,就是CAS方式.

      CAS的核心就是乐观的尝试,将线程的阻塞变成了线程的尝试,认为即使在不断尝试的代价也比阻塞后唤醒的代价要小.


    二 CAS

    CAS到底是什么呢? 其实就是一个JVM的指令,其中这个指令的执行是原子性的,也就是说不会被打断.

      我们看下AtomicInter的原子实现:  

        public final boolean compareAndSet(int expect, int update) {
            return unsafe.compareAndSwapInt(this, valueOffset, expect, update);
        }

    我们看到使用了unsafe完成了CAS操作,CAS代表的就是比较并且更新(交换).

        当现在的值等于期待值就会更新并且返回ture,

        不等于就会返回false,并且不会更新.

        public final int getAndUpdate(IntUnaryOperator updateFunction) {
            int prev, next;
            do {
                prev = get();
                next = updateFunction.applyAsInt(prev);
            } while (!compareAndSet(prev, next));
            return prev;
        }

    我们看上述的JDK的实现,使用了一个while循环不断试探是否是线程安全的.

      我们知道while体内的操作可能不是安全的,也就是会发生修改修改,那么现在的值就和期待值不一致,那么CAS保证不去更新.

      循环就会再次尝试,知道成功为止.

      通过这种尝试的方式保证操作是线程安全的.


    三 .ABA问题

    我们知道,CAS不保证循环体的过程,但是保证结果是正确的,这也就是说循环体内

      可能发生了一个自减操作,然后又做出了一个自增操作,这种情况下,期待值和实际值确实是一致的,但是不能保证原子性了.

    问题解决:

      解决的方式很简单,我们在原始的CAS之上加上一个时间戳,时间戳可以保证两次操作之间不应该有其它的操作.

      为此,出现了AtomicStampedReference这样的类可以保证线程安全.

  • 相关阅读:
    MySQL-基本sql命令
    Java for LeetCode 203 Remove Linked List Elements
    Java for LeetCode 202 Happy Number
    Java for LeetCode 201 Bitwise AND of Numbers Range
    Java for LeetCode 200 Number of Islands
    Java for LeetCode 199 Binary Tree Right Side View
    Java for LeetCode 198 House Robber
    Java for LeetCode 191 Number of 1 Bits
    Java for LeetCode 190 Reverse Bits
    Java for LeetCode 189 Rotate Array
  • 原文地址:https://www.cnblogs.com/trekxu/p/8996782.html
Copyright © 2011-2022 走看看