CAS是一种常用的硬件同步原语,即由一组计算机硬件提供的原子操作。
CAS的逻辑:
有三个参数:p-要改变变量的指针;old-旧值;new-新值。执行时先比较p和old值是不是相等,如果相等,就把new赋值给p,并返回true.否则不改变,返回false。
java在1.5之后引入CAS,主要放在JUC的atomic包下,如下图:
注意在使用CAS时出现ABA问题。
接下来用CAS 来实现转账问题(我们让账户的初始值为 0,然后启动多个协程来并发执行 10000 次转账,每次往账户中转入 1 元,全部转账执行完成后,账户中的余额应该正好是 10000 元)。
package cas; import org.springframework.util.StopWatch; import java.util.concurrent.CountDownLatch; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; /** * @author liupengr * @date 2020/2/20 19:40 */ public class CASTest implements Runnable{ private static AtomicInteger num=new AtomicInteger(0); private static CountDownLatch countDownLatch=new CountDownLatch(10000); @Override public void run() { while (!num.compareAndSet(num.get(),num.get()+1)){ } countDownLatch.countDown(); } public static void main(String[] args) throws InterruptedException { StopWatch stopWatch = new StopWatch(); stopWatch.start(); ThreadPoolExecutor executor = new ThreadPoolExecutor(10000, 10000, 1, TimeUnit.SECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 10000; i ++) { executor.execute(new CASTest()); } countDownLatch.await(); System.out.println(num.get()); System.out.println("消耗:" + stopWatch.getTotalTimeMillis() + "ms"); } }
运行结果: