关于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 接口进行突袭,高并发测压。
理应最后剩余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中进行自旋,知道交换成功,取反,跳出循环,并打印值!小样这次可以了吧?,哼!
结果很好,票价售卖正常,但是还有一个问题,那就是,如果僧多肉少,票就不够,不够的话,难不成无中生有??那不行,再改!!
第三版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() );
}
}
到这里使用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());
}
}
吞吐量对比
这里呢,我就不骂人了,啊哈哈哈哈哈,真好,hhh
总结
总的来说,一下午研究有蛮有意思的,虽然没什么用,但是确实加强了对AtomicReference的理解,不亏,哈哈哈