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()); } }
发文不易,请诸君且看且点赞,感谢你的支持!
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦