JUC原子变量操作类-AtomicLong

1. 简述

JUC 并发包中包含有 Atomiclnteger 、AtomicLong 和 AtomicBoolean 等原子性操作类 ,它们的原理类似
在这里插入图片描述

以AutomicLong为例:AtomicLong是原子性递增或者递减类,其内部使用Unsafe来实现

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

    // 1. 获取Unsafe实例
    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); }
    }

    private volatile long value;//实际变量值

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

为什么AutomicLong类中可以获得Unsafe的实例?
因为 AtomicLong类也是在 rt.jar 包下面的,AtomicLong 类就是通过 BootStarp 类加载器进行加载的


2. 常用方法

1. 递增递减操作

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

    /**
     * Atomically decrements by one the current value.
     *
     * @return the updated value
     */
     //调用 unsafe方法,原子性设置 value值为原始值-1 ,返回值为递减之后的值
    public final long decrementAndGet() {
        return unsafe.getAndAddLong(this, valueOffset, -1L) - 1L;
    }
    /**
     * Atomically increments by one the current value.
     *
     * @return the previous value
     */
     //调用unsafe方法,原子性设置value值为原始值+1, 返回值为原始值
    public final long getAndIncrement() {
        return unsafe.getAndAddLong(this, valueOffset, 1L);
    }
     /**
     * Atomically decrements by one the current value.
     *
     * @return the previous value
     */
     // //调用unsafe方法,原子性设置value值为原始值-1, 返回值为原始值
    public final long getAndDecrement() {
        return unsafe.getAndAddLong(this, valueOffset, -1L);
    }


如上代码内部都是通过调用 Unsafe getAndAddLong方法来实现操作,这个函数是个原子性操作,这里第一个参数是 AtomicLong 实例的引用 ,第二个参数是 value 变量在 AtomicLong 中的偏移值,第三个参数value要递增或递减的值

public final long getAndAddLong(Object paramObject , long paramLong1 , long
			paramLong2)
			long l ;
			do
			l = getLongvolatile(paramObject , paramLongl) ;
			) while (!compareAndSwapLong(paramObject , paramLong1 , l, l + paramLong2) );
			return l ;
			//如果当前数值是l(期待原子变量值是l)  则将原子变量值更新为l+paramLong2(如果在更新之前有其他的线程增加了原子变量值,则此时不相等
			//继续CAS比较)
}

2. compareAndSet(long expect, long update)方法

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

3. 代码实践

package innerlock;

import java.util.concurrent.atomic.AtomicLong;

public class AutomicLongDemo {
	private static AtomicLong count=new AtomicLong();//count初值为0
	private static int []arr1= {0,1,2,3,0,1,2,3,0,0};//4个0
	private static int []arr2= {1,0,2,0,5,0,6,7,0,9};//4个0
	public static void main(String[] args) throws InterruptedException {
		
		Thread t1=new Thread() {
			public void run() {
				int sz=arr1.length;
				for(int i=0;i<sz;i++)
				{
					if(arr1[i]==0)
						count.incrementAndGet();
				}
			}
		};
		Thread t2=new Thread() {
			public void run() {
				int sz=arr2.length;
				for(int i=0;i<sz;i++)
				{
					if(arr2[i]==0)
						count.incrementAndGet();
				}
			}
		};
		t1.start();
		t2.start();
		t1.join();
		t2.join();//等待t1 t2线程执行结束
		System.out.println("0的个数:"+count.get());
	}

}

在这里插入图片描述

上述代码使用两个线程分别统计arr1和arr2中的0的个数,在没有原子类的情况下,
实现计数器需要使用一定的同步措施,比如使用synchronized 关键字等 , 但是这些都是阻塞算法 ,
对性能有一定损耗 ,而原子操作类都使用 CAS 非阻塞算法 ,性能更好。但是在高并发情况下 AtomicLong 还会存在性能问题 。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodePanda@GPF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值