AtomicReference理解

AtomicReference理解

chuxiwen 11,584 2022-09-15

关于AtomicReference的理解

AtomicReference作为atomic包中的类,它保证了i++问题的原子性,其中的 boolean compareAndSet(V expect, V update) 方法,可以理解为在值交换成功后返回true,如果交换失败返回false。这一点尤其重要。

问题来源

在web项目的商品售卖问题中,在高并发下使用Javase知识解决通常加锁进行解决,使用ReentrantLock或者加synchronized关键字,因为以前浅学了JUC所以想用AtomicReference进行解决。然后!然后一下午就过去了!!焯!!

Good类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Goods {

    private  Integer number = 500;

}

GoodsController

@RestController
public class GoodsController {

    @Autowired
    private GoodServiceImpl goodService;

    @GetMapping("/good/reduce")
    public String reduce(){
        goodService.reduce();
        return "reduce over ~~";
    }
}

第一版GoodServiceImpl


private  AtomicReference<Goods> goodReference = new AtomicReference<>(new Goods());

    public void reduce(){        
        goodReference.compareAndSet(goodReference.get(),new Goods(goodReference.get().getNumber() - 1));
        System.out.println("剩余库存" + goodReference.get().getNumber());
    }

当我兴奋的开始测试时,呵呵了
因为Good默认500,所以我在jmeter定义一个500线程的线程组,对 /good/reduce 接口进行突袭,高并发测压。
AtomicReference1
理应最后剩余0件物品,但是取出现剩余。???可能是学的不熟悉,知识掌握不足,所以我差点以为自己发现了jdk的bug,哈哈哈哈c。

后来,想起来了,Atomic是解决i++原子问题,如果不能交换,那这次访问不就相当于没访问吗??什么也没有处理,只是返回了false,然后没有后续了,所以应该在返回false进行处理一下,那就写个自旋锁叭!

第二版GoodServiceImpl

    private  AtomicReference<Goods> goodReference = new AtomicReference<>(new Goods());

    public void reduce(){

        while (!goodReference.compareAndSet(goodReference.get(),new Goods(goodReference.get().getNumber() - 1))){
                
        }
        System.out.println(goodReference.get().toString() +"剩余库存:" + goodReference.get().getNumber() );
        
    }

如果无法交换值,也就是没有售卖成功,就在while中进行自旋,知道交换成功,取反,跳出循环,并打印值!小样这次可以了吧?,哼!
AtomicReference2
结果很好,票价售卖正常,但是还有一个问题,那就是,如果僧多肉少,票就不够,不够的话,难不成无中生有??那不行,再改!!

第三版GoodServiceImpl

    private  AtomicReference<Goods> goodReference = new AtomicReference<>(new Goods());

    public void reduce(){
        if(goodReference.get().getNumber() > 0){
            while (!goodReference.compareAndSet(goodReference.get(),new Goods(goodReference.get().getNumber() - 1))){
                if(goodReference.get().getNumber() <= 0){
                    break;
                }
            }
            System.out.println(goodReference.get().toString() +"剩余库存:" + goodReference.get().getNumber() );
        }
    }

AtomicReference3
到这里使用AtomicReference解决抢票问题,看似大功告成了,但是性能咋样呢?

使用synchronized

    private Goods goods = new Goods();

    public synchronized void reduce(){
        if(goods.getNumber() > 0){
            goods.setNumber(goods.getNumber() - 1);
            System.out.println("余额: " + goods.getNumber());
        }
    }

吞吐量对比
AtomicReference4

这里呢,我就不骂人了,啊哈哈哈哈哈,真好,hhh

总结

总的来说,一下午研究有蛮有意思的,虽然没什么用,但是确实加强了对AtomicReference的理解,不亏,哈哈哈


# Java 学习