Java中CAS方法的学习整理
1、引出CAS的需求
/** * * * 需求:开发一个网站需要对用户量进行统计,用户每发送一个请求访问量就加1,如何实现 * 模拟100个人同时访问,每个人发起10次请求,统计结果应该是1000次。 * * */
2、代码实现
public class Zdycas { private static volatile int count = 0; public static void main(String[] args) throws InterruptedException{ Long start = System.currentTimeMillis(); System.out.println("开始时间是"+start); CountDownLatch countDownLatch = new CountDownLatch(10); for(int j = 0;j< 10; j++){ new Thread(()->{ try{ for (int i = 0; i < 100; i++) { getCount(); } }catch (Exception e){ }finally { countDownLatch.countDown(); } }).start(); } countDownLatch.await(); Long end = System.currentTimeMillis(); System.out.println("结束时间是"+end); /** * * 1、测试的结果是count的值很难达到1000 * 原因:count++ 不是原子性操作分为三部分 * (1)把count 赋值给A A=count * (2)A+1 赋值给B * (3)把B赋值给count * volatile 能保证内存可见行以及禁止指令重排,但是保证不了count++变成一个原子性的操作。 * 2、使用synchronized、可重入锁、原子锁等方式 * synchronized 锁效率太低了 * 3、自定义一个cas方法 * (1)cas定义:CAS是英文单词Compare And Swap的缩写,翻译过来就是比较并替换。 * (2)compareAndSwap()方法:CAS机制当中使用了3个基本操作数:内存地址V,旧的预期值A,要修改的新值B。 * 更新一个变量的时候,只有当变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B。 * 4、CAS存在的问题 * (1)CPU开销较大:在并发量比较高的情况下,如果许多线程反复尝试更新某一个变量,却又一直更新不成功,循环往复, * 会给CPU带来很大的压力。比如 getCount()方法中的while循环 * (2)不能保证代码块的原子性:CAS机制所保证的只是一个变量的原子性操作,而不能保证整个代码块的原子性。 * 比如需要保证3个变量共同进行原子性的更新,就不得不使用Synchronized了 * (3)ABA问题:这是CAS机制最大的问题所在。 * 5、java cas 常用的api * public final native boolean compareAndSwapObject(Object var1,long var2,Object var4,Object var5) * public final native boolean compareAndSwapInt(Object var1,long var2,int var4,int var5) * public final native boolean compareAndSwapLong(Object var1,long var2,Long var4,Long var6) * * var1:表示要操作的对象 * var2:表示要操作对象中属性的偏移值 * var4:表示需要修改的数据的期望值 * var5:表示需要修改的新值 * * * 6、java cas 的原理是什么 * CAS通过调用JNI的代码实现,JNI :java native interface,它允许java通过调用它来调用其他语言。而comapreAndSwapxxx * 系列方法就是就是借助C语言来调用cpu底层指令实现的比较和替换。这些cpu的底层指令是原子性的。 * */ System.out.println(count+"main"); System.out.println("花费的时间是"+ (end-start)); } //这个是原来的getCount 方法 // public static void getCount() throws InterruptedException{ // TimeUnit.MILLISECONDS.sleep(5); // count++; // } public static void getCount() throws InterruptedException{ TimeUnit.MILLISECONDS.sleep(5); // count++; int expectCount; //这里是一个自旋锁 while (! compareAndSwap(expectCount = count,expectCount + 1)){} } //自定义的cas方法。 /** * * * * @param expectCount * @param newCount * @return */ public static synchronized boolean compareAndSwap(int expectCount,int newCount){ //判断当前线程的count 和期望的count(expectCount)是否一致 if(count == expectCount){ count = newCount; return true; } return false; //这里使用java自带的方式 // return atomicInteger.compareAndSet(expectCount,newCount); }