[toc]java
什么是原子性操做,按照官方的解析:原子操做不能在一个中间操做中中止,要么所有成功要么所有失败。(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
传统的锁实现比较笨重,若是程序中须要对某些计算变量实现原子性,是用java的锁会很笨重。并且给资源加锁若是控制不得当的话,容易出现死锁的现象。而CAS的出现就是为了解决在无锁的状况下也能够实现对于 资源的原子操做。
+ CAS容易产生ABA问题,就是一个内存地址V,值是A。有一个a线程要去修改它的值,此时有一个b线程把A的值改成了B,而后再改回A,此时对于a线程来讲,它对于b线程的修改操做时无感知的。为了解决ABA问题,引入了版本号。全部 线程修改一个内存的值前要先获取值的版本号,修改完后须要更新版本号。这彷佛就须要使用AtomicStampedReference来操做了。若是是不关心值是否被修改过的状况,不须要考虑ABA问题。 + 由于CAS会以自旋的方式索引指望值,若是一直没有索引到指望值。为了防止一直自旋下去,cpu会设置必定的阈值,超过阈值后就会挂起这个线程,让出cpu。
/** * 演示带版本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); } } }