AtomicInteger的使用

  在之前一篇volatile学习里面提到过了,volatile修饰的变量只是保证内存可见性,无法保证原子性,可能出现写冲突。要想保证线程安全,需要使用AtomicInteger。具体代码如下:

public class AtomicTest {
    public static AtomicInteger race=new AtomicInteger(0);
    public static void increase(){
        race.incrementAndGet();
    }
    private static final int THREADS_COUNT=20;
    public static void main(String[] args){
        Thread[] threads=new Thread[THREADS_COUNT];
        for(int i=0;i<THREADS_COUNT;i++){
            threads[i]=new Thread(new Runnable() {
                @Override
                public void run() {
                    for(int i=0;i<10000;i++){
                        increase();
                    }
                }
            });
            threads[i].start();
        }
        while(Thread.activeCount()>1){
            Thread.yield();
            System.out.println(race);
        }
    }
}

 

运行结果为200000,若是把变量用volatile修饰,然后increase方法替换成race++,那么最后得到的结果基本不为200000,且每一次得到的结果都可能是不同的。AtomicInteger的incrementAndGet是通过unsafe的getAndAddInt来实现的,而后者的代码如下:

public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

        return var5;
    }

 

  其中var1是调用unsafe的AtomicInteger对象,而var2是用来记录value本身在内存的编译地址的,这个记录,也主要是为了在更新操作在内存中找到value的位置,方便比较。而var5则是AtomicInteger的value值,被valotile修饰,当冲突时因为内存可见性,操作失败的线程可以看到修改成功的线程修改后的最新值。compareAndSwapInt亦即CAS,是原子操作,它的作用是若原值为var5即在这之间没发生过修改,那么设置为新值var5 + var4。AtomicInteger方法不是互斥同步的,而是非阻塞同步,也就是乐观锁,而前者被称为悲观锁。

  悲观锁认为冲突经常会发生,所以直接上锁,强制所有线程一次有且只有一条线程能操作,严格保证串行性。而乐观锁认为冲突很少发生,先进行操作,之后检查有没有冲突,若发生了冲突再采取其他补偿措施(最常见的补偿措施就是不断地重试,直到成功为止)。两者并无优劣之分,使用场景不同而已。若是冲突经常发生,那么采用乐观锁场景中,每次操作只有一条线程成功,失败的线程会不断尝试然后不断冲突,性能可能很差,但若是冲突很少发生,那么悲观锁那样一次只允许一条线程读写那么效率就太低了。乐观锁是通过检查版本号来检测是否发生冲突的,而版本号每次修改成功时+1。你每次需要修改值时带上版本号,若是你的版本号与当前一致那么修改成功,若是中间被其他线程修改了,那么版本号就与你的不一样了,你只能请求最新的版本号然后尝试着再次修改直到成功为止。像版本号这样单向增加的比较好,若是用原值来作为比较的标准的话,有可能会发生中间有人把原值加1另外一人把原值减1,然后轮到你的时候你以为原值在这中间没有变化而可能产生歧义,亦即ABA问题。而版本号只要发生了修改都会增加而无论操作是什么。

posted on 2017-11-20 15:34  一个人的合唱  阅读(2749)  评论(0编辑  收藏  举报