并发编程—3Cas原子操做

[toc]java

3.CAS原子操做

什么是原子性操做,按照官方的解析:原子操做不能在一个中间操做中中止,要么所有成功要么所有失败。(An atomic action cannot stop in the middle: it either happens completely, or it doesn't happen at all. No side effects of an atomic action are visible until the action is complete.),app

-- 除了long和double的读写,其余的引用变量的读写操做都是原子性的 -- 若是加了volatile关键字,全部的引用变量的读写操做都是原子性的。 -- 原子操做不会被其余的线程干扰。可是会存在内存不一致(consistency memory)的问题。可是使用关键字volatile能够大大减小这个风险。 -- 线程修改volatile变量的时候,会在这个变量上面和其余的读取该变量的读线程上面创建一个happens-before的关系。保证写线程对该变量的修改对其余的读线程是可见的。ide

compare and swap.在一个内存地址V,一个指望值A,一个新值B。若是在V上面是指望的A值,那么用B值去替换。不然经过自旋方式(死循环)一直到找到指望值位置。atom

3.1 为何要有CAS,传统的锁有什么弊端

传统的锁实现比较笨重,若是程序中须要对某些计算变量实现原子性,是用java的锁会很笨重。并且给资源加锁若是控制不得当的话,容易出现死锁的现象。而CAS的出现就是为了解决在无锁的状况下也能够实现对于
资源的原子操做。

3.2 CAS的问题

+ CAS容易产生ABA问题,就是一个内存地址V,值是A。有一个a线程要去修改它的值,此时有一个b线程把A的值改成了B,而后再改回A,此时对于a线程来讲,它对于b线程的修改操做时无感知的。为了解决ABA问题,引入了版本号。全部
线程修改一个内存的值前要先获取值的版本号,修改完后须要更新版本号。这彷佛就须要使用AtomicStampedReference来操做了。若是是不关心值是否被修改过的状况,不须要考虑ABA问题。
+ 由于CAS会以自旋的方式索引指望值,若是一直没有索引到指望值。为了防止一直自旋下去,cpu会设置必定的阈值,超过阈值后就会挂起这个线程,让出cpu。

3.3 举例

/**
 * 演示带版本Stamp的AtomicStampedReference使用
 * compareAndSet方法,须要指定老的版本号,若是设置成功返回true,不然返回false
 * @author 45027056
 *
 */
public class UseAtomicReferenceWithStamp {
	static String name = "luke";
	AtomicStampedReference atomicStampedReference = new AtomicStampedReference(name,0);
	public static void main(String[] args) {
		UseAtomicReferenceWithStamp demo = new UseAtomicReferenceWithStamp();
		demo.new SuccessThread().start();
		de mo.new FailThread().start();
		System.out.println("local name is...:"+ name);
	}
	
	class SuccessThread extends Thread{
		int oldStamp = atomicStampedReference.getStamp();
		String oldReferenct = (String) atomicStampedReference.getReference();
		@Override
		public void run() {
			boolean result = atomicStampedReference.compareAndSet(oldReferenct, "joe1", 0, 1);
			System.out.println("refernce is :" + atomicStampedReference.getReference());
			System.out.println("stamp is :" + atomicStampedReference.getStamp());
			System.out.println("result is :" + result);
		}
	}
	
	class FailThread extends Thread{
		int oldStamp = atomicStampedReference.getStamp();
		String oldReferenct = (String) atomicStampedReference.getReference();
		@Override
		public void run() {	
			boolean result = atomicStampedReference.compareAndSet(oldReferenct, "joe2", 0, 1);
			System.out.println("refernce is" + atomicStampedReference.getReference());
			System.out.println("stamp is" + atomicStampedReference.getStamp());
			System.out.println("result is :" + result);
		}
	}
}
相关文章
相关标签/搜索