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);
}