并发编程-Day07

一、无锁(cas)
1.1 jdk提供了AtomicInteger类无锁实现原子操作

@Slf4j(topic = "c.Test08")
public class Test08 {
    public static void main(String[] args) throws InterruptedException {
        CasAcount casAcount = new CasAcount(10000);
        for (int i = 0; i < 1000; i++) {
            new Thread(()->{
                casAcount.withdrawBlance(10);
            }).start();
        }

        Thread.sleep(2000);
        log.debug("{}",casAcount.getBlance());

    }
}

class  CasAcount implements Acount{

    private AtomicInteger blance = new AtomicInteger();

    public CasAcount(int value){
        this.blance.set(value);
    }

    @Override
    public int getBlance() {
        return this.blance.get();
    }

    @Override
    public void withdrawBlance(int count) {
        while(true){
            int blanceTemlate = getBlance();
            int res = blanceTemlate - count;
            if(this.blance.compareAndSet(blanceTemlate,res))//cas比较并设置
                break;
        }
    }
}

interface Acount{
   int getBlance();

   void withdrawBlance(int count);
}

1.2 cas原理

其实CAS的底层是lock cmpxchg 指令(X86架构),在单核CPU和多核CPU下都能够保证【比较-交换】的原子性。cas是配合volatile的使用,才能比较的时候获取最新值。

二、Atomic的使用

2.1AtomicInteger和AtomicReference的使用

@Slf4j(topic = "c.Test09")
public class Test09 {
    public static void main(String[] args) {
        AtomicInteger atomicInteger = new AtomicInteger(10);
        updateAndGet(atomicInteger,i->i*2);
        System.out.println(atomicInteger.get());
    }

    public static void updateAndGet(AtomicInteger i, IntUnaryOperator intUnaryOperator){
        while(true){
            int pre = i.get();
            int next = intUnaryOperator.applyAsInt(pre);
            if(i.compareAndSet(pre,next))
                break;
        }
    }
}

后面后接口式参数,可以自由操作。

如果要保护引用类型,需要使用AtomicReference


@Slf4j(topic = "c.Test10")
public class Test10 {
    public static void main(String[] args) {
        BigDecimalCas bigDecimalCas = new BigDecimalCas(new BigDecimal(20));
        bigDecimalCas.withdraw(new BigDecimal(15.3));
        System.out.println(bigDecimalCas.get());
    }
}

class BigDecimalCas{
    private AtomicReference<BigDecimal> blance;

    public BigDecimalCas(BigDecimal b){
        blance = new AtomicReference<>();
        this.blance.set(b);
    }

    public void withdraw(BigDecimal b){
        while(true){
            BigDecimal pre = blance.get();
            BigDecimal next = pre.subtract(b);
            if(blance.compareAndSet(pre,next))
                break;
        }
    }

    public BigDecimal get(){
        return blance.get();
    }
}

2.2 关于ABA问题
cas只关注要旧值和最新的值是否一致,但不能排除A->B->A,这对于主线程是无知觉的,所以需要添加版本号,每改动,版本号就加1。(AtomicStampedReference类实现)

2.3 原子数组

函数式接口传递

  • Supplier为无中生有,即()->new int[x]
  • Function<T,Integer>为一个参数一个结果,即(arr)->arr.length
  • Comsumer为一个参数无结果,即()->{}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值