CAS

什么是CAS?

CAS 是英文单词Compare And Swap的缩写,翻译过来就是比较并交换的意思。
CAS中有三个基本的操作数:内存地址V、旧的预期值A、要修改的值B,如果要更新一个变量的时候,只有当内存地址V == 旧的预期值A,也就是当且仅当:变量的预期值A和内存地址V当中的实际值相同时,才会将内存地址V对应的值修改为B
这样说可能有些抽象,下面看一张图:
在这里插入图片描述

CAS的缺点:

  1. CPU开销大
    在并发量很高的情况下,如果有多个线程反复的尝试去更新某一个新的变量,却一直不能更新成功的时候,循环往复,会给CPU带来很大的压力。
  2. 不能保证代码块的原子性,只能保证一个变量的原子操作。
  3. ABA的问题
    这是CAS机制最大的问题所在

代码示例

//代码一:下面这段代码最后打印的结果有可能会小于200
public class CountTest{
	public static int count = 0;
	public static void main(String [] args){
		//开启两个线程
		for(int i = 0;i<2;i++){
			new Thread(
				new Runnable(){
					public void run(){
						try{
							Thread.sleep(10);
						}catch(InterruptedException e){
							e.printStackTrace();
						}
						//在每个线程中,让count的值自增100次
						for(int j= 0;j<100;j++){
							count ++;
						}
					}
				}
			).start();
		}
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.print("count= "+count);
	}
}

//代码二(加"synchronized"):下面这段代码最后打印的结果一定是200
public class CountTest{
	public static int count = 0;
	public static void main(String [] args){
		//开启两个线程
		for(int i = 0;i<2;i++){
			new Thread(
				new Runnable(){
					public void run(){
						try{
							Thread.sleep(10);
						}catch(InterruptedException e){
							e.printStackTrace();
						}
						//在每个线程中,让count的值自增100次
						for(int j= 0;j<100;j++){
							synchronized(CountTest.class){
								count ++;
							}
						}
					}
				}
			).start();
		}
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.print("count= "+count);
	}
}

//代码三(使用"CAS"操作):下面这段代码最后打印的结果一定是200
所谓原子操作类,指的是java.util.concurrent.atomic包下,一系列以Atomic开头的包装类。例如AtomicBoolean,AtomicInteger,AtomicLong。它们分别用于Boolean,Integer,Long类型的原子性操作。

public class CountTest{
	//public static int count = 0;
	public static AtomicInteger count = new AtomicInteger(0);
	public static void main(String [] args){
		//开启两个线程
		for(int i = 0;i<2;i++){
			new Thread(
				new Runnable(){
					public void run(){
						try{
							Thread.sleep(10);
						}catch(InterruptedException e){
							e.printStackTrace();
						}
						//在每个线程中,让count的值自增100次
						for(int j= 0;j<100;j++){
							count.increamentAndGet();
						}
					}
				}
			).start();
		}
		try{
			Thread.sleep(2000);
		}catch(InterruptedException e){
			e.printStackTrace();
		}
		System.out.print("count= "+count);
	}
}

这两种方式的性能比较:

Synchronized关键字会让没有得到锁的线程进入BLOCKED 状态,而后在争夺到锁资源后恢复为RUNNINGABLE 状态,这个过程中涉及到操作系统用户模式 和 内核模式间来回切换,这样的切换代价很高,尽管在jdk1.6以后 Synchronized 关键字做了优化,增加了从偏向锁到轻量级锁再到重量级锁的过渡,但是在最终转变为重量级锁之后,性能仍然很低。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值