java多线程系列5 atomic简介

先看一个例子,AtomicInteger 实现的线程安全的累加器

public class AtomicIntTest {
	public static void main(String[] args) {
		AddRunnable addRunnable = new AddRunnable();
		Thread myThread1 = new Thread(addRunnable);
		Thread myThread2 = new Thread(addRunnable);
		myThread1.start();
		myThread2.start();
		try {
			myThread1.join();
			myThread2.join();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}

		System.out.println(addRunnable.count);
	}

}

class AddRunnable implements Runnable {
	AtomicInteger count = new AtomicInteger();

	@Override
	public void run() {
		for (int i = 0; i < 100000; i++) {
			count.incrementAndGet();
		}
	}

}

AtomicInteger源码分析

       下面通过AtomicInteger的源码来看一下是怎么在没有锁的情况下保证数据正确性。首先看一下incrementAndGet方法的实现

      

public final int incrementAndGet() {  
    for (;;) {  
        int current = get();  
        int next = current + 1;  
        if (compareAndSet(current, next))  
            return next;  
    }  
}  

public final boolean compareAndSet(int expect, int update) {     
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update);  
}  

  注意::valueOffset叫做 偏移量 我们知道valueOffset指向的地址对应的值就是原始变量的值 执行逻辑就是 expect 和valueOffset 比较 相同 就替换成 update 不同继续循环

 

 总结:

     

虽然基于CAS的线程安全机制很好很高效,但要说的是,并非所有线程安全都可以用这样的方法来实现,这只适合一些粒度比较小,型如计数器这样的需求用起来才有效,否则也不会有锁的存在了。实际来发中,用锁的情况还是较多。

并发越高,失败的次数会越多,CAS如果长时间不成功,会极大的增加CPU的开销。(毕竟死循环嘛) 因此CAS不适合竞争十分频繁的场景。

3 CAS只能保证一个共享变量的原子操作。当对多个共享变量操作时,CAS就无法保证操作的原子性,这时就可以用锁,或者把多个共享变量合并成一个共享变量来操作。使用AtomicReference。

posted on 2017-05-11 19:05  一只小蜗牛12138  阅读(166)  评论(0编辑  收藏  举报

导航