原子变量操作类

JUC简介

在 Java 5.0 提供了 java.util.concurrent (简称JUC )包,在此包中增加了在并发编程中很常用的实用工具类,用于定义类似于线程的自定义子系统,包括线程池、异步 IO 和轻量级任务框架。提供可调的、灵活的线程池。还提供了设计用于多线程上下文中的 Collection 实现等。

在JUC并发包中包含有AtomicInteger,AtomicLong,AtomicBoolean等基于CAS操作的原子操作类。他们原理相似,下面讲解AtomicLong类。它可以原子性递增或递减,内部通过Unsafe来实现。

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

    // 获得Unsafe实例
    private static final Unsafe unsafe = Unsafe.getUnsafe();
    
    //获得long值偏移量
    private static final long valueOffset;

	  //判断JVM是否支持Long类型的无锁CAS操作
    static final boolean VM_SUPPORTS_LONG_CAS = VMSupportsCS8();

    //本地方法。。
    private static native boolean VMSupportsCS8();

	 //静态代码块
    static {
        try {
            获得偏移量
            valueOffset = unsafe.objectFieldOffset
                (AtomicLong.class.getDeclaredField("value"));
        } catch (Exception ex) { throw new Error(ex); }
    }

	 //实际值
    private volatile long value;

    public AtomicLong(long initialValue) {
        value = initialValue;
    }

    public AtomicLong() {
    }
}

Unsafe类

在jdk中提供了Unsafe类来实现CAS操作,该类中的所有方法都是本地方法(Native),下面是Unsafe几个重要方法

long object FieldOffset(Field field)方法, 负责获得指定变量在所属类中的内存偏移量,该偏移量只能在Unsafe方法中访问指定函数才能使用

long native getLongVolatile(Object obj,long offset)方法,负责获得对象obj中指定偏移量offset的变量所对应的值

AtomicLong

递增递减操作

	 //获得递增后的值
    public final long incrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L;
    }

	 //获得递减后的值
    public final long decrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
    }
    //获得递增前的值
    public final long getAndIncrement() {
        return unsafe.getAndAddLong(this, valueOffset, 1L);
    }
    获得递减前的值
    public final long getAndDecrement() {
        return unsafe.getAndAddLong(this, valueOffset, -1L);
    }

上面的递增递减操作都是调用了Unsafe的getAndAddLong()方法来实现的,该函数时原子性操作。

    //参数一代表AtomicLong实例的引用,
    //参数二代表AtomicLong的value变量的偏移量
    //参数三代表要改变的值
    public final long getAndAddLong(Object var1, long var2, long var4) {
        long var6;
        do {
            var6 = this.getLongVolatile(var1, var2);//获得初始值
            //如果获得的初始值不相等则继续循环直到相等
        } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4));

        return var6;
    }

例子

public class TestAtomic {
    public static void main(String[] args) throws InterruptedException {
        for (int i=0;i<10;i++){
            Thread thread=new Thread(new CountThread(),"线程"+i);
            thread.start();
            thread.join();
        }
        System.out.println(CountThread.value);
    }
    public static class CountThread implements Runnable{

        public static AtomicLong value=new AtomicLong();
        @Override
        public void run() {
            for (int i=0;i<1000;i++){
                value.incrementAndGet();
            }
        }
    }
}

总结

在没有原子类的情况下,要实现多线程计数器需要同步措施,例如使用synchronized关键字,但这会大大影响性能,而这些Atomic原子类实现了CAS非堵塞算法,提升了性能。不过在高并发的情况下还是会影响性能,在JDK8中提供了在高并发性能更好的LongAdder类,下次再来写了。

猜你喜欢

转载自blog.csdn.net/printf_scnaf/article/details/106731521
今日推荐