手记

Java并发包中的原子变量操作类

JUC并发包提供了一系列的原子操作类,这些类都是使用非阻塞算法(CAS)实现的,相比于使用锁来实现,这些原子操作类在性能上更好一些。


JUC并发包中包含有AtomicInteger、AtomicLong和AtomicBoolean等原子性操作类,它们的原理相似。

这里以AtomicLong为例进行说明,AtomicLong是原子性递增或者递减类,它是使用Unsafe来实现的。   

AtomicLong通过CAS提供了非阻塞的原子性操作。   

其源码如下:

public class AtomicLong extends Number implements java.io.Serializable {
    private static final long serialVersionUID = 1927816293512124184L;

    // 1. 获取Unsafe实例 AtomicLong类是通过BootStarp类加载器进行加载的
    private static final Unsafe unsafe = Unsafe.getUnsafe();
   // 2. 存放变量value的偏移量
    private static final long valueOffset;

    // 3. 判断JVM是否支持Long类型无锁CAS
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();
    private static native boolean VMSupportsCS8();

    static {
        try {
          // 4. 获取value在AtomicLong中的偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicLong.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

    // 5. 实际变量值,声明为volatile是为了在多线程环境下保证其内存可见性,value是具体存放计数的变量。
    private volatile long value;

    // 6. 有参构造方法
    public AtomicLong(long initialValue) {
        value = initialValue;
    }

    // 7. 无参构造方法
    public AtomicLong() {
    }

    // 8. 获取值
    public final long get() {
        return value;
    }

    // 9. 写入值
    public final void set(long newValue) {
        value = newValue;
    }

   
    public final void lazySet(long newValue) {
        unsafe.putOrderedLong(this, valueOffset, newValue);
    }

   
    public final long getAndSet(long newValue) {
        return unsafe.getAndSetLong(this, valueOffset, newValue);
    }

    // 调用unsafe的compareAndSwapLong方法,如果原子变量中的value值等于expect,则使用update值更新该值并返回true,否则返回false。
    public final boolean compareAndSet(long expect, long update) {
        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    }

    //同上
    public final boolean weakCompareAndSet(long expect, long update) {
        return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
    }

    // 调用unsafe方法,原子性设置value值为原始值+1,返回值为原始值
    public final long getAndIncrement() {
        return unsafe.getAndAddLong(this, valueOffset, 1L);
    }

    // 调用unsafe方法,原子性设置value值为原始值-1,返回值为原始值
    public final long getAndDecrement() {
        return unsafe.getAndAddLong(this, valueOffset, -1L);
    }

    // 调用unsafe方法,原子性设置value值加上delta,并返回
    public final long getAndAdd(long delta) {
        return unsafe.getAndAddLong(this, valueOffset, delta);
    }

    // 调用unsafe方法,原子性设置value值为原始值+1,返回值为递增后的值
    public final long incrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
    }

    // 调用unsafe方法,原子性设置value值为原始值-1,返回值为递减后的值
    public final long decrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
    }

    // 调用unsafe方法,原子性设置value值为原始值 + delta,返回值为加操作后的值
    public final long addAndGet(long delta) {
        return unsafe.getAndAddLong(this, valueOffset, delta) + delta;
    }

  
    public final long getAndUpdate(LongUnaryOperator updateFunction) {
        long prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsLong(prev);
        } while (!compareAndSet(prev, next));
        return prev;
    }

   
    public final long updateAndGet(LongUnaryOperator updateFunction) {
        long prev, next;
        do {
            prev = get();
            next = updateFunction.applyAsLong(prev);
        } while (!compareAndSet(prev, next));
        return next;
    }

   
    public final long getAndAccumulate(long x,
                                       LongBinaryOperator accumulatorFunction) {
        long prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsLong(prev, x);
        } while (!compareAndSet(prev, next));
        return prev;
    }

  
    public final long accumulateAndGet(long x,
                                       LongBinaryOperator accumulatorFunction) {
        long prev, next;
        do {
            prev = get();
            next = accumulatorFunction.applyAsLong(prev, x);
        } while (!compareAndSet(prev, next));
        return next;
    }

   
    public String toString() {
        return Long.toString(get());
    }

    // 获取int类型的值
    public int intValue() {
        return (int)get();
    }

    // 获取long类型的值
    public long longValue() {
        return get();
    }

    // 获取float类型的值
    public float floatValue() {
        return (float)get();
    }

    // 获取double类型的值
    public double doubleValue() {
        return (double)get();
    }

}

从源码中看出,AtomicLong的递增或递减方法都是通过调用Unsafe的getAndAddLong方法来实现操作。      

getAndAddLong方法是个原子性操作,在这里它的第一个参数是AtomicLong实例的引用,第二个参数是value变量在AtomicLong中的偏移量,第三个参数是要设置的第二个变量的值。  


使用AtomicLong的实例代码见thread20


关于AtomicInteger和AtomicBoolean与AtomicLong原理类似,就不多说了。

 代码示例:

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @ClassName: AtomicLongTest
 * @Description: 使用AtomicLong统计0的个数
 * @Author: liuhefei
 * @Date: 2019/12/8
 * @blog: https://www.imooc.com/u/1323320/articles
 **/
public class AtomicLongTest {

    //1. 创建Long类型原子计数器
    private static AtomicLong atomicLong = new AtomicLong();
    //private static AtomicInteger atomicInteger = new AtomicInteger();
    //private static AtomicBoolean atomicBoolean = new AtomicBoolean();

    //2. 创建数据源
    private static Integer[] arrayOne = new Integer[]{0, 1, 4, 0, 9, 100, 0, 1000, 54, 60, 20, 12, 0};
    private static Integer[] arrayTwo = new Integer[]{0, 100, 30, 4, 6, 0, 8, 87, 0, 23, 56, 0, 3, 6 , 10, 0};

    public static void main(String[] args) throws InterruptedException {
        //线程one统计arrayOne中0的个数
        Thread threadOne = new Thread(new Runnable() {
            @Override
            public void run() {
                int size = arrayOne.length;
                for(int i = 0; i < size; i++){
                    if(arrayOne[i].intValue() == 0){
                        atomicLong.incrementAndGet();  //调用unsafe方法,原子性设置value值为原始值+1,并返回递增后的值
                    }
                }
            }
        });

        //线程two统计arrayTwo中0的个数
        Thread threadTwo = new Thread(new Runnable() {
            @Override
            public void run() {
                int size = arrayTwo.length;
                for(int i = 0; i < size; i++){
                    if(arrayTwo[i].intValue() == 0){
                        atomicLong.incrementAndGet();  //调用unsafe方法,原子性设置value值为原始值+1,并返回递增后的值
                    }
                }
            }
        });

        //启动线程
        threadOne.start();
        threadTwo.start();

        //等待线程执行完毕
        threadOne.join();
        threadTwo.join();

        System.out.println("count 0 = " + atomicLong.get());
    }
}

发文不易,请诸君且看且点赞,感谢你的支持!



0人推荐
随时随地看视频
慕课网APP