J.U.C atomic AtomicInteger解析

      不少状况下咱们只是须要简单的,高效,线程安全的递增递减方法。注意,这里有三个条件:简单,意味着程序员尽量少的底层或者实现起来比较简单;高效,意味着耗用资源要少,程序处理速度要快; 线程安全也很是重要,这个在多线程下能保证数据的正确性。这三个条件看起来比较简单,可是实现起来却难以使人满意。html

      一般状况下,在Java里面, ++i或者-- i不是线程安全的,这里面有三个独立的操做:读取变量当前值,为该值+1 /-1,而后写会新的值。在没有额外资源能够利用的状况下,只能使用加锁才能保证读-改-写这三个操做证的‘"原子性"。java

     在J.U.C(Doug Lea)为加入jdk以前,是采用纯Java实现的,因而不可避免的采用了synchronized关键字。程序员

public final synchronized void set(int newValue);

public final synchronized int getAndSet(int newValue);

public final synchronized int incrementAndGet();

     同时在变量上使用了volatile(后面详述)来保证get()的时候不用加锁。尽管synchronized的代价仍是很高,可是在没有JNI的手段下纯Java语言仍是不能实现此操做的。安全

     来看看java.util.cocurrent.atomic.AtomicInteger开始:多线程

     

int addAndGet(int delta);
     //以原子方式将给定值与当前值想家。实际上就是等于线程安全版本的 i += delta

boolean compareAndSet(int expect, int update);
    //若是当前值 == 预期值,则以原子方式将该值设置为给定的更新值。若是
    //更新成功就返回true, 不然就返回false, 而且不修改原值

int decrementAndGet();
    //以原子方式将当前值减1,至关于线程安全版本的--i操做。

int get(); //得到当前值。

int getAndAdd(int delta);
     //以原子方式将给定值与当前值相加,至关于线程版本的 t = i;  i +=    //delat; return t;

int getAndDecrement();
    //以原子方式将当前值减1,至关于线程安全版本的i--;

int getAndIncrement();
   //以原子方式将当前值加1,至关于线程安全版本的i++;

int getAndSet();
  //以原子方式设定给定值,并返回旧值;

int incrementAndGet();
   //以原子方式将当前值加1,至关于线程安全版本的++i;

       看几个实现:测试

  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); }
    }

    private volatile int value;

     调用sun.misc.Unsafe类实现cas操做(历史版权缘由,Unsafe源码看不了),获取该对象value成员的内存地址;this

  public final boolean compareAndSet(int expect, int update) {
        return unsafe.compareAndSwapInt(this, valueOffset, expect, update); //根据unsafe的cas操做,返回true or false
    }

     看一下上面API的实现:atom

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

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

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


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

       方法实现整体差很少,for(;;)死循环,读取当前值,根据相应的加减cas操做,成功从for中返回,失败不一样重试;spa

       测试用例以下:.net

import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Test;

import static org.junit.Assert.*;
public class AtomicIntegerTest {
 
    @Test
    public void testAll() throws InterruptedException {
        final AtomicInteger value = new AtomicInteger(10);
        assertEquals(value.compareAndSet(1, 2), false);
        assertEquals(value.get(), 10);
        assertTrue(value.compareAndSet(10, 3));
        assertEquals(value.get(), 3);
        value.set(0);
        
        //
        assertEquals(value.incrementAndGet(), 1);
        assertEquals(value.getAndAdd(2), 1);
        assertEquals(value.getAndSet(5), 3);
        assertEquals(value.get(), 5);
        
        // final
        final int threadSize = 5;
        Thread[] threads = new Thread[threadSize];
        for (int i = 0; i < threadSize; i++) {
            threads[i] = new Thread() {
                public void run() {
                value.incrementAndGet();    
                }
            };
        }
        for (Thread t : threads) {
            t.start();
        }
        
        for (Thread t : threads) {
            t.join();
        }
        //
        assertEquals(value.get(), 5 + threadSize);
    }
}

 

      原文来至:http://www.blogjava.net/xylz/archive/2010/07/08/325587.html

相关文章
相关标签/搜索