CAS无锁机制

最近在学习并发编程时,看到了CAS无锁机制,特地写个博客分享下。

  1. 首先先了解一个原子类
    java.util.concurrent.atomic包:原子类的小工具包,支持在单个变量上解除锁的线程安全编程
    原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读-改-写操作。AtomicInteger 表示一个int类型的值,并提供了 get 和 set 方法,这些 Volatile 类型的int变量在读取和写入上有着相同的内存语义。
    下面先写个demo(原子类AtomicInteger)看一下两个线程操作一个全局变量的线程安全问题
public class Test implements Runnable {
	private static Integer count = 1;
	private static AtomicInteger atomic = new AtomicInteger();//线程安全

	@Override
	public void run() {
		while (true) {
			int count = getCountAtomic();
			System.out.println(count);
			if (count >= 50) {
				break;
			}
		}
	}

	public synchronized Integer getCount() {
		try {
			Thread.sleep(50);
		} catch (Exception e) {
			// TODO: handle exception
		}

		return count++;
	}

	public Integer getCountAtomic() {
		try {
			Thread.sleep(50);
		} catch (Exception e) {
			// TODO: handle exception
		}
		//每次自增 i++,底层没有用锁,用的时CAS无锁机制
		return atomic.incrementAndGet();
	}

	public static void main(String[] args) {
		Test test = new Test();
		Thread t1 = new Thread(test );
		Thread t2 = new Thread(test );
		t1.start();
		t2.start();
	}

}

结果时按顺序1,2,3,4.。。。。。

  1. CAS原理

原子类 线程安全 非阻塞,底层没有锁,底层实现原理CAS无锁技术,就是比较再交换:CAS compare and swap。了解CAS无锁技术,首先要了解JVM内存模型。(下面这文章还可以,可以去看看)
https://www.cnblogs.com/dingyingsi/p/3760447.html
CAS包含三个参数(V,E,N)V表示要更新的变量,E表示预期值,N表示新值,仅当V值等于E值时,才会将V的值设为N,如果V值和E值不同,则说明已经有其他线程做了更新,则当前线程什么都不做。最后,CAS返回当前V的真实值。
第一个参数V:V=需要去更新的变量(主内存的共享变量)
E=预期值(本地内存的副本)
N=新值
如果V=E(主内存的值与本地内存的值一致,说明没人修改),将V的值设置为N。
如果V不等于E(主内存的值跟本地内存的不一致),已经被修改。这样的情况下,就将E的值设置成V的值,重新刷新,再比较。看下源码,无非就是一个无限刷新,知道V和E的值一致。

public final int getAndAddInt(Object o, long offset, int delta) {
        int v;
        do {
            v = getIntVolatile(o, offset);
        } while (!compareAndSwapInt(o, offset, v, v + delta));
        return v;
    }



/** 
	 * Atomically increments by one the current value. 
	 * 
	 * @return the updated value 
	 */  
	public final int incrementAndGet() {  
	    for (;;) {  

	        int current = get();  

	        int next = current + 1;  
	 
	        if (compareAndSet(current, next))  
	        
	            return next;  
	    }  
	}  

  1. CAS缺点(ABA问题)
    当一个线程在对共享变量进行操作时,读取到的值为A,如果在这段期间曾经被改成B,然后又改回A,那CAS操作就会误认为它从来没有被修改过。
    解决办法:java并发包中提供了一个带有标记的原子引用类AtomicStampedReference,它可以通过控制变量值的版本来保证CAS的正确性,相当于给主内存的变量的值给了个标记。
    https://www.cnblogs.com/java20130722/p/3206742.html

你可能感兴趣的:(Java)