硬件同步原语(CAS、FAA)和锁 来实现异步并发转账

硬件同步原语

硬件同步原语(Atomic Hardware Primitives)是由计算机硬件提供的一组原子操作,我们比较常用的原语主要是 CAS 和 FAA 这两种。
原语:原子操作,只要当前线程执行完毕之后,才会切换下一个线程执行。

CAS

CAS(CompareAndSwap),即先比较,再交换。


<< atomic >>
// p: 要修改的变量的指针。
// old: 旧值
// new: 新值
function cas(p : pointer to int, old : int, new : int) returns bool {
    if *p ≠ old {
        return false
    }
    *p ← new
    return true
}

机制:当在该线程的工作内存中的旧值,与要修改变量的指针的值(也就是在主内存)相同时,表明此时没有线程修改它。就会把要修改的值修改为新值。

FAA

Fetch And Add

<< atomic >>
function faa(p : pointer to int, inc : int) returns int {
    int value <- *location
    *p <- value + inc
    return value
}

语义:先获取变量 p 当前的值 value,然后给变量 p 增加 inc,最后返回变量 p 之前的值 value

实现

Java Synchronized、ReentrantLock

package com.rpq.leetcode.lock;

import java.util.concurrent.BlockingDeque;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用锁实现异步并发实现转账
 * @author renpeiqian
 * @date 2021/7/17 10:29
 * @since
 */
public class LockTest {

    //定义初始余额为0
    private static  int balance=0;
    public static void main(String[] args) {

        //定义循环次数
        int count=1000000;
        //ReentrantLock底层就是cas
        ReentrantLock lock =new ReentrantLock();

        long start = System.currentTimeMillis();
        for (int i = 0; i <count ; i++) {
			//CompletableFuture.runAsync(()-> transferSynchronized(1));
            CompletableFuture.runAsync(()-> transfer(1,lock));
        }
        while (balance < count) {
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println(end-start);
        System.out.println(balance);

    }
    /**
     * @Description 转账业务
     * @Param [amount, lock]
     * @return void
     */
    private static void transfer(int amount,ReentrantLock lock){
        //开锁
        // 使用阻塞锁,长搭配try finally 块来保证锁的释放。并且lock.lock 方法与try之间不能发生任何异常
        lock.lock();
        try{
            //转账
            balance += amount;
        }finally {
            lock.unlock();
        }

    }
    
    /**
     * @Description 使用synchronized同步锁实现转帐
     * @Param [amount]
     * @return void
     */
    private static  void transferSynchronized(int amount){

        synchronized (LockTest.class){
            balance += amount;
        }
    }

}

CAS、FAA

package com.rpq.leetcode.lock;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author renpeiqian
 * 使用硬件原语cas、Faa实现转账业务
 * @date 2021/7/17 11:23
 * @since
 */
public class CasFaaLock {

    //使用原子整形类创建初始余额为0
    private static AtomicInteger balance =new AtomicInteger(0);

    public static void main(String[] args) {
        int count=1000000;
        long start = System.currentTimeMillis();
        for (int i = 0; i <count ; i++) {
            CompletableFuture.runAsync(()-> casTransfer(1));
        }
        while(balance.get()<count){
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        long end = System.currentTimeMillis();
        System.out.println(end-start);
        System.out.println(balance);
    }

    /**
     * @Description cas(compare and swap )
     * @Param [amount] 转账数目
     * @return void
     */
    private static void casTransfer(int amount){
        //死循环 相当于自旋
        for (;;){
            //获取旧值
            int old = balance.get();
            int newBalance = old + amount;
            //如果当前线程工作内存中值与主内存值保持一直,可以修改该值
            if (balance.compareAndSet(old,newBalance)){
                //修改成功,终止循环
                break;
            }
            //修改失败,说明其他线程已经修改过,自旋重新尝试修改
        }
    }


    /**
     * @Description
     * 使用FAA(Fetch And Add 即取到值进行自增) 实现转账
     * 对于FAA,通过查找资料,jdk1.8在调用sun.misc.Unsafe#getAndAddInt方法时,
     * 会根据系统底层是否支持FAA,来决定是使用FAA还是CAS。
     * @Param [amount]
     * @return void
     */
    private static void faaTransfer(int amount){
        //获取值然后在增加
        balance.getAndAdd(amount);
    }

}
上一篇:Game


下一篇:Android解析Asset目录下的json文件