java-CAS 原理

来源:互联网 发布:classic动作数据下载 编辑:程序博客网 时间:2024/06/10 05:49

最近感兴趣的内容到J.U.C包中了,当然了,对于这个包我的理解还是只看见大门,首先,自己没机会在项目中实战,其次,平时很少练手,再其次,最近才看,所以很多文章都是网上大牛写的,自己翻译过来,就当做逼自己重新看一遍了。

首先谈谈自己对于锁的恐惧吧,其实对于每个初级人员来说,锁是一个高深的问题,一般情况下我估计所有的初级人员来说的话,都很少使用,即使使用了,也是简单的synchronized吧,对于其他的锁我估计都很少使用,笔者最近使用了redis锁,说来其实很讽刺啊,单服务器的锁还没玩的溜,都开始装逼使用redis锁了,hh。

我对于使用synchronized的理解:

1) 当前线程持有锁的话,其他线程就挂起了。

2) 如果在有竞争的情况下呢?加锁和释放锁肯定会带来性能上的消耗吧。

3) 如果一个线程的优先级高,但是确在等待一个优先级低的线程释放锁,是否会有问题(这个只是猜测了,本人其实不知道),纯粹来源于网络知识。

两种锁:悲观锁和乐观锁。

synchronized就是一个悲观锁,会导致所有的线程等待当前线程释放锁之后才能进入。

乐观锁就是每次不加锁而是假设没有冲突去完成某项操作,如果因为冲突失败了就重试,直至成功,乐观锁的一种实现就是CAS Compare And Swap.


CAS有三个操作数----内存旧值(V),预期原值(A) 和新值(B)。CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。


CAS利用了CPU的CAS指令和 JNI的来完成java的非阻塞算法。

关于ABA问题不去记录了,现在已近不存在这个问题了。


具体来看AtomicInteger这个类。Unsafe这个类就是java代码和计算机底层进行交互时使用的代码。这个我不想关注,知道即可。看其中的valueOffset是什么?CAS是拿期望的值和原本的值作比较,相同的话就更新为新值,那这个valueOffset其实就是原本的值。这个方法拿到的就是一个原本的值的内存地址(为什么要看内存地址,就是去解决ABA问题的)。

// setup to use Unsafe.compareAndSwapInt for updates    private static final Unsafe unsafe = Unsafe.getUnsafe();    private static final long valueOffset;    static {      try {        valueOffset = unsafe.objectFieldOffset            (AtomicInteger.class.getDeclaredField("value"));      } catch (Exception ex) { throw new Error(ex); }    }
value是volatile的,volatile变量在内存中对任意线程都是可见的,但是它不能保证原子性

private volatile int value;

来看看这个方法。内部是个无线循环,这就是上文提到的乐观锁,假设没有竞争,每个程序都是在无线循环,直至条件满足,return掉。

current和next这两个操作都是非线程安全的,关键的就在于compareAndSet这个方法。

    /**     * Atomically increments by one the current value.     *     * @return the previous value     */    public final int getAndIncrement() {        for (;;) {            int current = get();            int next = current + 1;            if (compareAndSet(current, next))                return current;        }    }
这边对于get方法来说只传入了current和next的值,但是底层计算时并不是这样,this,当前对象的地址,valueOffset的为原本值的相对对象的偏移量,expect为期望的值,update为新值,也就是expect的值和valueOffset处的值相等时,更新为新值。
/**     * Atomically sets the value to the given updated value     * if the current value {@code ==} the expected value.     *     * @param expect the expected value     * @param update the new value     * @return true if successful. False return indicates that     * the actual value was not equal to the expected value.     */    public final boolean compareAndSet(int expect, int update) {        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);    }

其他方法多多少少都是基于此,就不一一看了。

但是AtomicInteger并不能来测试啊,看不见输出啊, 看不见每个线程的旧值,新值啊。怎么办呢?自己实现一个呗。

首先要结局unsafe这个玩意儿吧,至于怎么获取,www.baidu.com,可以找到吧,好像只提供了一个获取方式,反射获取。

public class UnsafeFactory {    private static Unsafe unsafe = null;    static {        try {            Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");            unsafeField.setAccessible(true);            unsafe = (Unsafe) unsafeField.get(null);        } catch (Exception e) {            e.printStackTrace();            throw new Error("unsafe init error");        }    }    public static Unsafe get() {        return unsafe;    }}
自己实现的,参考AtomicInteger就行了,没什么难处

public class UserAtomicInteger {    private static final Unsafe unsafe = UnsafeFactory.get();    private volatile int value;    private static final long valueOffset;    static {        try {            valueOffset = unsafe.objectFieldOffset(UserAtomicInteger.class                    .getDeclaredField("value"));        } catch (Exception ex) {            throw new Error(ex);        }    }    public UserAtomicInteger(int initialValue) {        value = initialValue;    }    public void compareAndSwap(){        for(;;){            try{                System.out.println(Thread.currentThread()+"当前值为: "+value);                int oldValue = value;                int newValue = oldValue + 1;                if(compareAndSet(oldValue,newValue)){                    System.out.println("线程: "+ Thread.currentThread() + "赋值成功。value: "+ value+ " old : "+ oldValue + " new : "+ newValue);                }            }catch (Exception e){                System.out.println(e.getMessage());            }        }    }    private boolean compareAndSet(int expect, int update) {        return unsafe.compareAndSwapInt(this, valueOffset, expect, update);    }}


测试类,起4个线程,while一直去运行。

public class TestAtomic {    public static void main(String[] args) {        UserAtomicInteger a = new UserAtomicInteger(1);        MyThread t1 = new MyThread(a);        MyThread t2 = new MyThread(a);        MyThread t3 = new MyThread(a);        MyThread t4 = new MyThread(a);        t1.start();        t2.start();        t3.start();        t4.start();    }}class MyThread extends Thread{    UserAtomicInteger use;    public MyThread(UserAtomicInteger use){        this.use = use;    }    @Override    public void run() {        try{            while (true){               use.compareAndSwap();            }        }catch (Exception e){            e.getMessage();        }    }}

可以看见输出,

看见第5行和第7行,线程1读取到为3,线程3读取到也为3,但是线程1进入了CAS过程,然后值为4了,线程3虽然读到了是3,但是此时值已变,最新值是4

Thread[Thread-0,5,main]当前值为: 1线程: Thread[Thread-0,5,main]赋值成功。value: 2 old : 1 new : 2Thread[Thread-2,5,main]当前值为: 2线程: Thread[Thread-2,5,main]赋值成功。value: 3 old : 2 new : 3Thread[Thread-1,5,main]当前值为: 3线程: Thread[Thread-1,5,main]赋值成功。value: 4 old : 3 new : 4Thread[Thread-3,5,main]当前值为: 3线程: Thread[Thread-3,5,main]赋值成功。value: 5 old : 4 new : 5Thread[Thread-0,5,main]当前值为: 5线程: Thread[Thread-0,5,main]赋值成功。value: 6 old : 5 new : 6Thread[Thread-2,5,main]当前值为: 6线程: Thread[Thread-2,5,main]赋值成功。value: 7 old : 6 new : 7Thread[Thread-3,5,main]当前值为: 7线程: Thread[Thread-3,5,main]赋值成功。value: 8 old : 7 new : 8Thread[Thread-1,5,main]当前值为: 7线程: Thread[Thread-1,5,main]赋值成功。value: 9 old : 8 new : 9Thread[Thread-0,5,main]当前值为: 9线程: Thread[Thread-0,5,main]赋值成功。value: 10 old : 9 new : 10Thread[Thread-2,5,main]当前值为: 10线程: Thread[Thread-2,5,main]赋值成功。value: 11 old : 10 new : 11Thread[Thread-1,5,main]当前值为: 11线程: Thread[Thread-1,5,main]赋值成功。value: 12 old : 11 new : 12Thread[Thread-3,5,main]当前值为: 11线程: Thread[Thread-3,5,main]赋值成功。value: 13 old : 12 new : 13Thread[Thread-0,5,main]当前值为: 13线程: Thread[Thread-0,5,main]赋值成功。value: 14 old : 13 new : 14Thread[Thread-2,5,main]当前值为: 14线程: Thread[Thread-2,5,main]赋值成功。value: 15 old : 14 new : 15Thread[Thread-3,5,main]当前值为: 15线程: Thread[Thread-3,5,main]赋值成功。value: 16 old : 15 new : 16Thread[Thread-1,5,main]当前值为: 16线程: Thread[Thread-1,5,main]赋值成功。value: 17 old : 16 new : 17Thread[Thread-0,5,main]当前值为: 17线程: Thread[Thread-0,5,main]赋值成功。value: 18 old : 17 new : 18Thread[Thread-2,5,main]当前值为: 18线程: Thread[Thread-2,5,main]赋值成功。value: 19 old : 18 new : 19Thread[Thread-1,5,main]当前值为: 19线程: Thread[Thread-1,5,main]赋值成功。value: 20 old : 19 new : 20Thread[Thread-3,5,main]当前值为: 20线程: Thread[Thread-3,5,main]赋值成功。value: 21 old : 20 new : 21


0 0
原创粉丝点击