Java CAS(CompareAndSwap)

本文介绍了Java并发编程中的CAS(Compare and Swap)操作,包括其工作原理、特点和应用场景。详细讲解了ABA问题及其解决方案——原子引用,并通过示例展示了如何使用AtomicStampedReference解决。此外,还手写了基于CAS的自旋锁实现,讨论了其在并发控制中的作用。
摘要由CSDN通过智能技术生成

CAS比较并交换

简介

如果线程的期望值和主物理内存的值一样,便将值写入主物理内存,如果不同,本次修改失败,并重新获取值。

特点

不加锁,并发性强。

底层实现

汇编:lock cmpxchg

使用场景

AtomicInteger等类底层就是CAS实现

//AtmoicInteger
public final int getAndIncrement(){
	return unsafe.getAndAddInt(this, valueOffset, 1);
}

//unsafe.getAndAddInt
//var2内存偏移
public final int getAndAddInt( Object var1, long var2 , int var4){
	int var5;
	do {
		var5 = this.getIntVolatile(var1,var2);
		//如果之前获取的var5在主内存中没被修改,则将新增写入,如果已经修改,则再次读取var5,直到成功写入内存
	}while( !this.compareAndSwapInt( var1, var2, var5, var5+var4));
	return var5;
}

CAS缺点

1、如果CAS一直不成功,循环时间可能长,开销大。
2、只能保证一个变量的原子操作(多个变量需要加锁)
3、引起ABA问题
线程一和线程二都把A放到自己的工作空间,但二号线程快,它把A改成B并放回主物理内存,一段时间后又把B改成A放回主物理内存。此时线程一回来,虽然期望值和实际值一样,但中间可能被改过很多次。

在解决ABA问题前先了解什么是原子引用


public class Main{
	@Getter
	@ToString
	@AllArgsConstructor
	static class User{
		String name;
		int age;
	}
	 
	public static void main( String[] args){
		User a = new User("a",10);
		User b = newUser("b",20);
		AtomicReference<User> atomicReference = new AtomicReference<>();
		atomicReference.set( a );//线程安全
		atomicReference.compareAndSet(a , b);//线程安全,如果当前是a,就将其改为b,否则不改
	}
}

ABA解决方法:加时间戳的原子引用

public class Main{
	static AtomicReference<Integer> atomicReference = newAtomicReference<>(100);
	static AtomicStampedReference<Integer> atomicStampedReference = new AtomicStampedReference<>(100,1);
	public static void main(String[] args ){
		System.out.println("===========产生ABA==========");
		new Thread( () -> {
			atomicReference.compareAndSet(100,101);
			atomicReference.compareAndSet(101,100);
		},"t1").start();
		 
		newThread( () -> {
			try{ TimeUnit.SECONDS.sleep(1); }catch( InterruptedException e ){ e.printStackTrace(); }
			System.out.println( Thread.currentThread().getName()+"修改成功吗?"+atomicReference.compareAndSet(100,2021)+"\t"+atomicReference.get());
		},"t2").start();
		 
		try{ TimeUnit.SECONDS.sleep(3); }catch( InterruptedException e ){e.printStackTrace();}
		System.out.println("=============ABA问题解决=============");
		 
		new Thread( () -> {
			int stamp = atomicStampedReference.getStamp();
			try{ TimeUnit.SECONDS.sleep(1); }catch( InterruptedException e ){e.printStackTrace();}
			atomicStampedReference.compareAndSet(100,101,stamp,stamp+1);
			atomicStampedReference.compareAndSet(101,100,atomicStampedReference.getStamp(),atomicStampedReference.getStamp()+1);
			System.out.println(Thread.currentThread().getName()+"完成,现在版本号:"+atomicStampedReference.getStamp());
		},"t3").start();
		 
		new Thread( () -> {
			int stamp = atomicStampedReference.getStamp();
			try{ TimeUnit.SECONDS.sleep(3); }catch(InterruptedExceptione){e.printStackTrace();}
			System.out.println(Thread.currentThread().getName()+"修改成功吗?"+atomicStampedReference.compareAndSet(100,101,stamp,stamp+1));
			System.out.println("原版本号"+stamp+"\t当前最新版本号"+atomicStampedReference.getStamp());
		},"t4").start();
	}
}

运行结果

=产生ABA
t2修改成功吗?true 2021
=ABA问题解决=
t3完成,现在版本号:3
t4修改成功吗?false
原版本号1 当前最新版本号3

手写自旋锁

public class SpinLock{
	AtomicReference<Thread> atomicReference = new AtomicReference<>();
	 
	public void lock(){
		Thread thread = Thread.currentThread();
		while( !atomicReference.compareAndSet(null,thread) );
		System.out.println(Thread.currentThread().getName()+"获取锁");
	}
	
	public void unlock(){
		Thread thread = Thread.currentThread();
		atomicReference.compareAndSet(thread,null);
		System.out.println(Thread.currentThread().getName()+"释放锁");
	}
	 
	public static void main(String[]args){
		SpinLock lock = new SpinLock();
		for(int i=0 ; i<5 ; i++){
			new Thread(()->{
				lock.lock();
				try{TimeUnit.SECONDS.sleep(2);}catch(InterruptedExceptione){e.printStackTrace();}
				lock.unlock();
			},String.valueOf(i)).start();
		}
	}
}

运行结果:
1获取锁
1释放锁
0获取锁
0释放锁
2获取锁
2释放锁
4获取锁
4释放锁
3获取锁
3释放锁

其他Java锁的介绍

https://blog.csdn.net/D1124615130/article/details/116160604

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值