• 并发之AtomicIntegerArray


    5 并发之AtomicIntegerArray
        该类是Java对Integer数组支持的原子性操作;在认识这个类之前我们先来看一个方法,这个方法是Integer类中的;
     public static int numberOfLeadingZeros(int i) {}
    看看官方的解释吧:返回具有至多单个 1 位的 int 值,在指定的 int 值中最高位(最左边)的 1 位的位置。
    看完官方的解释大家知道了吧;哈哈,说实话其实我也没能理解;但是这并不妨碍我们对该方法的使用;
    该方法直译过来就是抵达0位置的个数:
    先来看一段代码吧:
    public class IntegerArrayTest {
         public static void main(String[] args) {
             Integer a=1;
             Integer b=13;
             Integer c=25;
             /**
              * 0000 0000 0000 0000 0000 0000 0000 0000
              * 0000 0000 0000 0000 0000 0000 0000 0001   0的个数为31       1
              * 0000 0000 0000 0000 0000 0000 0000 1101   0的个数为28       13
              * 0000 0000 0000 0000 0000 0000 0001 1001   0的个数为27       25
              *   a的二进制为=1 最左边开始数起连续0的个数为31
              *   b的二进制为=1101 最左边开始数起连续0的个数为28
              *  c的二进制为=11001 最左边开始数起连续0的个数为27
              */
             System.out.println("a的二进制为="+Integer.toBinaryString(a)+" 最左边开始数起连续0的个数为"+Integer.numberOfLeadingZeros(a));
             System.out.println("b的二进制为="+Integer.toBinaryString(b)+" 最左边开始数起连续0的个数为"+Integer.numberOfLeadingZeros(b));
             System.out.println("c的二进制为="+Integer.toBinaryString(c)+" 最左边开始数起连续0的个数为"+Integer.numberOfLeadingZeros(c));
             
         }
    }
     
    public class AtomicIntegerArray implements java.io.Serializable {
        private static final long serialVersionUID = 2862133569453604235L;
      
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final int base = unsafe.arrayBaseOffset(int[].class);
        private static final int shift;
        private final int[] array;
     
        static {
            int scale = unsafe.arrayIndexScale(int[].class);
            if ((scale & (scale - 1)) != 0)
                throw new Error("data type scale not a power of two");
            shift = 31 - Integer.numberOfLeadingZeros(scale);
        }
    }
     
    在看上述的代码之前,我先来说一个问题:
        在AutomicInteger类中,value的值是使用了volatile修饰的;会对所有的线程立即可见;但是本身又不可以保证原子性的操作;那么为什么还要在该类中使用这个关键字呢?
        在这里我需要做一个补充说明;看如下的代码所示(是AutomicIntegerArray中的方法):
      
    1   /**
    2      * 原子性的设置一个值
    3      */
    4     public final void set(int i, int newValue) {
    5         unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
    6     }
    下面的源码是AutomicInteger类中的set()方法
      
     /**
         * 原子性的设置一个值
         */
        public final void set(int newValue) {
            value = newValue;
        }
     
    大家看到了吧,两个方法的本质是一样的,第一个方法使用了CAS算法,并且获原子性的设置了这个数组中元素的值;之所以使用volatile是对其它线程立马可见;这个才是最重要的原因;而对于lazySet()方法而言,是没有使用volatile关键字的;因为它对其他线程是属于赖设置的;也就是不能马上被其他线程可见;也就是说可以变量共享,但是使用了volatile将失去JVM的优化作用;原子性操作我认为大多数操作或者读的操作没有使用volatile的关键是读可以多线程共享,写不是共享的;其实CAS算法设计的就是乐观锁的思想;
    public static void automicIntegerArray() {
             /**
              * 创建一个原子性的数组,长度为5
              */
             AtomicIntegerArray atomicArray = new AtomicIntegerArray(5);
             /**
              * 设置第一个元素的值为5
              */
             atomicArray.set(0, 5);
             /**
              * 第一个元素减去1
              */
             int current = atomicArray.decrementAndGet(0);
             System.out.println("current = " + current);//current = 4
         }
    看AutomicIntegerArray的构造器
    /**
         * 创建一个原子性整※数组,并且长度为length;而且初始值都为0
         * elements initially zero.
         */
        public AtomicIntegerArray(int length) {
            array = new int[length];
        }
        
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    18.5 推挽输出和开漏输出区别
    19.3 Table 1-2.S3C2440A 289-Pin FBGA Pin Assignments (Sheet 4 of 9) (Continued)
    19.2 MEMORY CONTROLLER
    19.1 PORT CONTROL DESCRIPTIONS
    17.2 SourceInsight批量注释
    17.3 删除没用的project
    17.1 添加汇编文件并可索引
    16.2 在SecureCRT编写C程序不高亮显示
    16.1 解决SecureCRT的Home+End+Del不好用使用方法
    15.1 打开文件时的提示(不是dos格式)去掉头文件
  • 原文地址:https://www.cnblogs.com/gosaint/p/9053871.html
Copyright © 2020-2023  润新知