精华内容
下载资源
问答
  • 一个模块化的Less基础类库,包含Reset、栅格系统、原子类、常用class和浏览器兼容等模块。 ##使用: 首先在你的less里引入 coffce.less,再根据你的需要,调用各个模块的init初始化模块 npm install coffce-less // ...
  • 原子类css,提高css开发效率
  • 原子类

    千次阅读 2019-02-19 20:11:52
    什么是原子类  以前认为原子是不可分割的最小单位。故原子类可以认为其操作时不可分割的。  为什么要有原子类  对多线程访问同一变量,我们需要加锁,而锁是比较消耗性能的,jdk1.5之后,新增的原子操作类提供...

    什么是原子类

      以前认为原子是不可分割的最小单位。故原子类可以认为其操作时不可分割的。

      为什么要有原子类

        对多线程访问同一变量,我们需要加锁,而锁是比较消耗性能的,jdk1.5之后,新增的原子操作类提供了一种简单、性能高效、线程安全地更新一个变量的方式,这些类同样位于juc包下的atomic包下,发展到jdk1.8,该报共有17个类,囊括了原子更新基本类型、原子更新数组、原子更新新属性、原子更新引用。

      1.8新增的原子类

        DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、LongAccumulator、LongAdder

       大致可归为三类

           AtomicBoolean、AtomicIndteger、AutomicLong  元老级的原子更新,方法几乎一模一样

           DoubleAdder、LongAdder 对Double、Long的原子更新性能进行优化提升

           DoubleAccumulator、LongAccumlator 支持自定义运算

      原子更新数组类型

           AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

      原子的更新属性

           原子的更新某个类里的字段时,需要使用原子更新字段类,AtomicStampedReference、AtomicReference、FiledUpdater

          使用上述类是必须遵循以下原则

            字段必须是voliatile类型的,在线程之间共享变量时能保持可见性。

            字段的描述类型是与调用者的操作对象字段保持一致。

            也就是说调用者可以直接操作对象字段,那么就可以反射进行原子操作。

            对父类的字段,子类不能直接操作的,尽管子类可以访问父类的字段

            只能是实例变量,不能是类变量,也就是说不能加static关键字

            只能是可修改变量,不能使用final修饰变量,final的语义,不可更改。

            对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型                           (Integer/Long)

            如果需要修改包装类型就需要使用AtomicReferenceFieldUpdater。

    下面写几个原子类使用的简单例子

    1.AtomicIndteger实现一个线程安全的自增

    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * AtomicInteger  demo
     */
    public class AtomicIntegerDemo {
        private static AtomicInteger sum = new AtomicInteger(0);
    
        public static void  increase(){
            sum.incrementAndGet();
        }
    
        public static void main(String[] args) throws InterruptedException{
            for (int i=0;i<10;i++){
                new Thread(()->{
                    for (int j=0;j<10;j++){
                        increase();
                        System.out.println(sum);
                    }
                }).start();
    
            }
    
        }
    }

    2.LongAccumulator Long类型的原子运算

    import java.util.concurrent.atomic.LongAccumulator;
    
    public class LongAccumulatorDemo {
        public static void main(String[] args) {
            LongAccumulator longAccumulator = new LongAccumulator((left,right)->
            left<right?right:left,0l);
            longAccumulator.accumulate(3);
    
            System.out.println(longAccumulator.get());
    
            longAccumulator.accumulate(6);
    
            System.out.println(longAccumulator.get());
        }
    }

       运行结果

       

    3.AtomicIntegerArray 原子更新int数组元素

    import java.util.concurrent.atomic.AtomicIntegerArray;
    
    public class AtomicIntegerArrayDemo {
    
        public static void main(String[] args) {
            int[] arr = new int[]{3,2};
    
            AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
    
    
            System.out.println("arr数组下标为1的元素的值加3等于:"
                    +atomicIntegerArray.addAndGet(1, 3));
    
            System.out.println("arr数组下标为0的元素的值同2比较,较大的值为:"
                    +atomicIntegerArray.accumulateAndGet(0, 2, ((left, right) -> left>right?left:right)));
        }
    }

       

    4.原子更新属性,先创建一个简单的Student类,方便后面的测试

    public class Student {
        volatile long id;
        volatile String name;
    
        public Student(Long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }

      4.1AtomicLongFieldUpdater 更新long类型属性 ,AtomicReferenceFieldUpdater 更新String类型属性

    import java.util.concurrent.atomic.AtomicLongFieldUpdater;
    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
    
    public class AtomicFieldUpdaterDemo {
    
        public static void main(String[] args) {
            //更新long类型属性
            AtomicLongFieldUpdater<Student> atomicLongFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");
    
            Student student = new Student(1L,"lisi");
            atomicLongFieldUpdater.compareAndSet(student, 1L, 101l);
            System.out.println("更新long类型的属性id:"+student.getId());
    
            //更新包装类型属性
            AtomicReferenceFieldUpdater<Student,String> atomicReferenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class,"name" );
    
            atomicReferenceFieldUpdater.compareAndSet(student, "lisi", "zhangsan");
    
            System.out.println("更新String类型的属性name:"+student.getName());
        }
    
    }

    运行结果:

    展开全文
  • 主要介绍了深入了解Java atomic原子类的使用方法和原理,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,,需要的朋友可以参考下
  • 主要介绍了Java多线程Atomic包操作原子变量与原子类详解,简单介绍了Atomic,同时涉及java.util.concurrent中的原子变量,Atomic类的作用等相关内容,具有一定参考价值,需要的朋友可以了解下。
  • java原子类详解

    千次阅读 2020-07-21 17:16:56
    java原子类详解 什么原子类 原子类是具有原子性的类,原子性的意思是对于一组操作,要么全部执行成功,要么全部执行失败,不能只有其中某几个执行成功。 原子类作用 作用和锁有类似之处,是为了保证并发情况下的线程...

    java原子类详解

    什么原子类

    原子类是具有原子性的类,原子性的意思是对于一组操作,要么全部执行成功,要么全部执行失败,不能只有其中某几个执行成功。

    原子类作用

    作用和锁有类似之处,是为了保证并发情况下的线程安全。

    相对于锁的优势

    • 粒度更细
      原子变量可以把竞争范围缩小到变量级别,通常情况下锁的粒度也大于原子变量的粒度

    • 效率更高
      除了在高并发之外,使用原子类的效率往往比使用同步互斥锁的效率更高,因为原子类底层利用了CAS,不会阻塞线程。

    原子类种类

    在JDK中J.U.C包下提供了种类丰富的原子类,以下所示:

    类型具体类型
    Atomic* 基本类型原子类AtomicInteger、AtomicLong、AtomicBoolean
    Atomic*Array 数组类型原子类AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
    Atomic*Reference 引用类型原子类AtomicReference、AtomicStampedReference、AtomicMarkableReference
    Atomic*FieldUpdater 升级类型原子类AtomicIntegerfieldupdater、AtomicLongFieldUpdater、AtomicReferenceFieldUpdater
    Adder 累加器LongAdder、DoubleAdder
    Accumulator 积累器LongAccumulator、DoubleAccumulator

    AtomicInteger常用方法

    上面列举了J.U.C中提供的一些原子操作类,接下来从简单的AtomicInteger开始分析,来看看它的常用方法,其他的两种AtomicLong、AtomicBoolean和它相似

    方法作用
    public final int get()获取当前的值
    public final int getAndSet(int newValue)获取当前的值,并设置新的值
    public final int getAndIncrement() 获取当前的值,并自增+1
    public final int getAndDecrement() 获取当前的值,并自减-1
    public final int getAndAdd(int delta) 获取当前的值,并加上预期的值。getAndIncrement和getAndDecrement不满足,可使用当前方法
    boolean compareAndSet(int expect, int update) 如果输入的数值等于预期值,则以原子方式将该值更新为输入值(update)

    Array 数组类型原子类

    AtomicArray 数组类型原子类,数组里的元素,都可以保证其原子性,比如 AtomicIntegerArray 相当于把 AtomicInteger 聚合起来,组合成一个数组。我们如果想用一个每一个元素都具备原子性的数组的话, 就可以使用 AtomicArray

    该类包括:

    类名作用
    AtomicIntegerArray整形数组原子类
    AtomicLongArray长整形数组原子类
    AtomicReferenceArray引用类型数组原子类

    Atomic*Reference 引用类型原子类

    AtomicReference引用类型原子类,作用和AtomicInteger没有本质区别,AtomicReference是让一个对象保持原子性,而不局限一个变量。

    该种类所有类型:

    类名作用
    AtomicReference保证对象的原子性
    AtomicStampedReference它是对 AtomicReference 的升级,在此基础上还加了时间戳,用于解决 CAS 的 ABA 问题。
    AtomicMarkableReference和 AtomicReference 类似,多了一个绑定的布尔值,可以用于表示该对象已删除等场景。

    Atomic*FieldUpdater原子更新器

    原子类更新器主要用于对已经声明的非原子变量,为它增加原子性,让该变量拥有CAS操作的能力。
    该种类所有类型:

    类名作用
    AtomicIntegerFieldUpdater原子更新整形的更新器
    AtomicLongFieldUpdater原子更新长整形的更新器
    AtomicReferenceFieldUpdater原子更新引用的更新器

    这里使用AtomicIntegerFieldUpdater来举例说明:

    public class AtomicIntegerFieldUpdaterDemo implements Runnable {
    
        static Score useUpdaterScore;
        static Score unusedComputerScore;
    
        //声明原子更新类,泛型为Score类,更新的是"score"字段
        public static AtomicIntegerFieldUpdater<Score> scoreUpdater = AtomicIntegerFieldUpdater
                .newUpdater(Score.class, "score");
    
        @Override
        public void run() {
            for (int i = 0; i < 1000; i++) {
                //非原子操作直接自增
                unusedComputerScore.score++;
                //使用更新器更新字段,同样执行自增
                scoreUpdater.getAndIncrement(useUpdaterScore);
            }
        }
    
        public static class Score {
            volatile int score;
        }
    
        public static void main(String[] args) throws InterruptedException {
            useUpdaterScore = new Score();
            unusedComputerScore = new Score();
            AtomicIntegerFieldUpdaterDemo r = new AtomicIntegerFieldUpdaterDemo();
            Thread t1 = new Thread(r);
            Thread t2 = new Thread(r);
            t1.start();
            t2.start();
            t1.join();
            t2.join();
            System.out.println("普通变量的结果:" + unusedComputerScore.score);
            System.out.println("升级后的结果:" + useUpdaterScore.score);
        }
    }
    

    输出结果:
    普通变量的结果:1980
    升级后的结果:2000

    从结果可以看出,升级后结果是期望值。

    • 使用场景(相对于直接使用AtomicInteger)
      • 历史原因
        如果当前变量在之前开发版本中使用地方过多,这个时候为了不做大量改造,可以在需要原子性的时候,使用原子更新器
      • 少部分情况需要原子性的时候
        由于原子类型的变量比普通变量更耗资源。在大部分不需要原子性的时候,如果都设置成原子类型,这非常的耗资源。因此,我们可以再需要原子性的少数情况下,对当前变量使用AtomicIntegerFieldUpdater进行合理的升级。

    常见问题

    原子类是如何利用 CAS 保证线程安全的?

    以AtomicInteger为例,jdk 8实现,看怎么实现累加原子操作的

    public final int getAndAdd(int delta) {
        return unsafe.getAndAddInt(this, valueOffset, delta);
    }
    

    U是Unsafe类

    该方法实际调用的是,unsafe.getAndAddInt(this, VALUE, delta),这里先介绍一下Unsafe类。

    • Unsafe类
      Unsafe是CAS的核心类。由于java无法直接访问底层操作系统,而是需要通过本地方法来实现。JVM还是提供了Unsafe类,他提供了硬件层面的原子操作,可以直接操作内存的数据。

    接下来看一下AtomicInteger的一些关键代码

    public class AtomicInteger extends Number implements java.io.Serializable {
        private static final long serialVersionUID = 6214790243416807050L;
    
        private static final Unsafe unsafe = Unsafe.getUnsafe();
        private static final long valueOffset;
        private volatile int value;
    
        static {
            try {
                valueOffset = unsafe.objectFieldOffset(AtomicInteger.class.getDeclaredField("value"));
            } catch (Exception var1) {
                throw new Error(var1);
            }
        }
    
        private volatile int value;
    
        public final int get() {
            return value;
        }
        ......
    }
    
    

    首先获取Unsafe类型变量unsafe,并定义变量valueOffset,然后在静态代码块中value值在内存中的偏移地址,赋值给valueOffset变量。因为 Unsafe 就是根据内存偏移地址获取数据的原值的,这样我们就能通过 Unsafe 来实现 CAS 了。

    value是用volatile修饰的,他就是我们原子类存储值的变量,由于使用volatile修饰,所以在多线程中看到的value值都是同一份,保证了可见性。

    接下来看实际执行cas的地方。Unsafe的getAndAddInt()方法

    public final int getAndAddInt(Object var1, long var2, int var4) {
        int var5;
        do {
            var5 = this.getIntVolatile(var1, var2);
        } while(!this.compareAndSwapInt(var1, var2, var5, var5 +var4));
    
        return var5;
    }
    

    先看do-while循环,它是一个无限循环,知道满足条件才退出循环。do中的代码时,获取到当前内存中的值赋值给var5,var1是当前原子对象,var2是value在内存中的偏移量。此时var5就是此时原子类的数值。

    再看看while中的退出条件。compareAndSwapInt这个方法参数,他们的实际意义是:

    • 第一个参数 --> 当前原子类对象,即AtomicInteger 这个对象本身
    • 第二个参数 --> 当前值的内存偏移量,接触它可以获取到value的值
    • 第三个参数 --> 当前值,如果当前值不匹配,更新失败会返回false,开始下次循环。如果当前值匹配,同时更新成功,方法返回true,跳出循环,完成当前累加操作
    • 第四个参数 --> 期望值,即当前值加上累加的值。

    所以 compareAndSwapInt 方法的作用就是,判断如果现在原子类里 value 的值和之前获取到的 var5 相等的话,那么就把计算出来的 var5 + var4 给更新上去,所以说这行代码就实现了 CAS 的过程。

    总结一下,Unsafe 的 getAndAddInt 方法是通过循环 + CAS 的方式来实现的,在此过程中,它会通过 compareAndSwapInt 方法来尝试更新 value 的值,如果更新失败就重新获取,然后再次尝试更新,直到更新成功。

    AtomicInteger 在高并发下

    AtomicLong 高并发下存在的问题

    在并发情况下,如果我们需要实现计数器(例如下载任务数),可以利用AtomicInteger和AtomicLong,这样一来可以避免加锁和复杂的代码逻辑。虽然它们好用,但是也存在着一些问题。

    public class AtomicLongDemo {
     
       public static void main(String[] args) throws InterruptedException {
           AtomicLong counter = new AtomicLong(0);
           ExecutorService service = Executors.newFixedThreadPool(16);
           for (int i = 0; i < 100; i++) {
               service.submit(new Task(counter));
           }
     
           Thread.sleep(2000);
           System.out.println(counter.get());
       }
     
       static class Task implements Runnable {
     
           private final AtomicLong counter;
     
           public Task(AtomicLong counter) {
               this.counter = counter;
           }
     
           @Override
           public void run() {
               counter.incrementAndGet();
           }
       }
    }
    

    在这里,定义了一个为0的AtomicLong变量counter,然后创建了线程池数为16的线程池。然后执行100个任务。然后任务是执行counter.incrementAndGet()。结果毫无疑问是100,虽然并发执行,但是AtomicLong依然能保证incrementAndGet是一个原子操作,所以不会发生线程安全问题。

    不过我们仔细看细节,对于 AtomicLong 内部的 value 属性而言,也就是保存当前 AtomicLong 数值的属性,它是被 volatile 修饰的,所以它需要保证自身可见性。
    当线程1执行incrementAndGet操作更新成功后,会将值向主内存中修改,同时主内存会将其他线程的value给修改掉,而且CAS也会经常失败,这两个操作是非常耗资源的。

    如何改进AtomicLong 在高并发下性能

    在JDK 8中新增了LongAdder 类,来优化这一个问题。

    我们将上面例子中做小小的调整,将AtomicLong换成LongAdder,get()方法换成sum(),incrementAndGet()换成increment()

    public class LongAdderDemo {
     
       public static void main(String[] args) throws InterruptedException {
           LongAdder counter = new LongAdder();
           ExecutorService service = Executors.newFixedThreadPool(16);
           for (int i = 0; i < 100; i++) {
               service.submit(new Task(counter));
           }
     
           Thread.sleep(2000);
           System.out.println(counter.sum());
       }
       static class Task implements Runnable {
     
           private final LongAdder counter;
     
           public Task(LongAdder counter) {
               this.counter = counter;
           }
     
           @Override
           public void run() {
               counter.increment();
           }
       }
    }
    

    运行得到的结果还是100,但是运行速度比刚才AtomicLong实现要快。那么为什么LongAddr比AtomicLong快呢?

    LongAddr源码解析
    //集成自Striped64
    public class LongAdder extends Striped64 implements Serializable {}
    
    
    abstract class Striped64 extends Number {
        ......
         /**
         * 单元格表。如果为非null,则大小为2的幂。
         */
        transient volatile Cell[] cells;
    
        /**
         * 基本值,主要在没有争用时使用,也用作表初始化过程中的回退。通过CAS更新。
         */
        transient volatile long base;
    
        ......
    }
    

    LongAdder中引入了分段累加的概念,内部的Cell[]数组和base变量都参与了计数

    其中base在竞争不激烈的情况下,直接把累加的结果改到base变量上;
    在竞争激烈的时候,各个线程会分散累加到自己所对应的Cell[] 数组的某一个对象中,而不是公用一个。LongAdder这样分段的思想将不同线程到不同Cell上的修改,避免了大量的冲突,提升了并发性。更JDK 7 中的ConcurrentHashMap思想相似。

    竞争激烈的时候,LongAdder 会通过计算出每个线程的 hash 值来给线程分配到不同的 Cell 上去,每个 Cell 相当于是一个独立的计数器,这样一来就不会和其他的计数器干扰,Cell 之间并不存在竞争关系,所以在自加的过程中降低了冲突的概率。这个思想的本质就是空间换时间,所以会耗费更多的内存。

    最终的结果是通过LongAdder#sum()方法来获取的,将各个Cell值累计求和,再加上base返回。

    public long sum() {
       Cell[] as = cells;
       long sum = base;
       if (as != null) {
           for (Cell a : as)
               if (a != null)
                   sum += a.value;
       }
       return sum;
    }
    
    

    AtomicLong和LongAdder使用如何选择

    在低竞争的情况下,AtomicLong和LongAdder的性能相似;但是在竞争激烈的情况下,LongAdder 的预期吞吐量要高得多,经过试验,LongAdder 的吞吐量大约是 AtomicLong 的十倍,虽然性能提高了,但是LongAdder会耗费更多的空间

    • LongAdder 只提供了 add、increment 等简单的方法,适合的是统计求和计数的场景,场景比较单一
    • 而 AtomicLong 还具有 compareAndSet 等高级方法,可以应对除了加减之外的更复杂的需要 CAS 的场景。

    • 小结
      如果我们的场景仅仅是需要用到加和减操作的话,那么可以直接使用更高效的 LongAdder,但如果我们需要利用 CAS 比如 compareAndSet 等操作的话,就需要使用 AtomicLong 来完成。

    原子类 和 volatile的区别

    • volatile只保证可见性
      volatile只保证了可见性,而不能保证原子性。例如主内存中volatile int a=0,在两个线程中时,如果都同时获取当前的volatile修饰的变量值,但是都执行自增操作,由于两个线程都在之前获取了值即a=0,两线程都执行自增后都是a=1了,这是两个线程同时更新主内存中的a,最后得到的结果是a=1,这个就和预期值不一样,由于并没有保证获取和赋值这个操作的原子性,会有线程安全问题。

    • 原子类保证了可见性和原子性
      上面的例子可以使用原子类AtomicInteger来修复,将自增操作换成incrementAndGet(),底层通过CPU指令保证原子性,解决线程安全问题

    使用场景

    -使用场景
    volatile通常情况下,volatile 可以用来修饰 boolean 类型的标记位,因为对于标记位来讲,直接的赋值操作本身就是具备原子性的,再加上 volatile 保证了可见性,那么就是线程安全的了
    原子类对于先获取值,然后做一定修改,再赋值回去的操作,就需要原子类来保证原子性

    AtomicInteger 和 synchronized 的异同点

    相同点

    • 都能保证线程安全

    不同点

    -原理使用范围粒度性能
    AtomicInteger使用CAS来保证线程的原子性仅一个对象,少数场景使用竞争在变量级别乐观锁,低并发时性能好
    synchronized使用monitor锁来保证线程安全性。再执行同步代码之前,需要先获取到monitor锁,执行完毕,释放锁。既可以修饰一个方法,又可以修饰一段代码,可以根据我们的需要,非常灵活地去控制它的应用范围通常会大于变量级别悲观锁(jdk6之后锁升级优化后,低并发情况性能也不错),在高并发时由于AtomicInteger

    Java 8 中 Adder 和 Accumulator 有什么区别

    上面讲了Adder是通过CAS加分段思想来提高Atomic*的性能。

    而LongAccumulator是LongAdder的功能增强版,LongAccumulator在LongAdder只有数值加减的基础上提供自定义的函数操作。

    例如,下面代码

    public class LongAccumulatorDemo {
    
        public static void main(String[] args) throws InterruptedException {
            LongAccumulator accumulator = new LongAccumulator((x, y) -> x + y, 0);
            ExecutorService executor = Executors.newFixedThreadPool(8);
            IntStream.range(1, 10).forEach(i -> executor.submit(() -> accumulator.accumulate(i)));
    
            Thread.sleep(2000);
            System.out.println(accumulator.getThenReset());
        }
    }
    
    

    上面是使用8线程数的线程池累加0-9。最后获取到结果为45.

    x是上一次的结果,y是传入的新值。由于使用多线程,当前的方法只适用于即使执行顺序不同,结果依然一样的情况,即 交 换 性 \color{red}交换性

    下面几种场景适合使用:

    • 相加
    • 相乘
    • 最大值、最小值

    总结

    上面讲了原子类所有的种类、使用、及其原理,同时也介绍了各个原子类的使用场景,并且和volatile、synchronized做了对比。我们在实际开发中可以根据具体业务来选择适合的原子类使用。

    展开全文
  • Java中的原子类

    千次阅读 2020-12-11 09:00:00
    送你小心心记得关注我哦!在前面的内容中,我们已经学习了CAS的原理,所以对于学习本节来说会非常容易。本节介绍Java中的原子类是java.util.concurrent.atomic包下...

    送你小心心记得关注我哦!

    在前面的内容中,我们已经学习了CAS的原理,所以对于学习本节来说会非常容易。本节介绍Java中的原子类是java.util.concurrent.atomic包下的对象,他们之所以有原子性的共性,都来源于CAS,可见CAS的重要性。对于原子类变量的操作是不会存在并发性问题的,不需要使用同步手段进行并发控制。它底层自身的实现即可保证变量的可见性以及操作的原子性,一般我们可以使用AtomicInteger,AtomicLong等实现计数器等功能,利用AtomicBoolean实现标志位等功能。

    原子类是JDK5提供的,当时只有12个原子类,发展到JDK8时,又多出了4个原子类,如下图2-25所示,红色框内为JDK8新增加的。

    图2-25 Java16个原子类

    下面我们来对这些原子类进行分类讲解。

     

    2.10.1原子更新基本类型

    l AtomicBoolean:  原子更新布尔类型。

    l AtomicInteger:    原子更新整型。

    l AtomicLong:       原子更新长整型。

    我们以AtomicInteger为例,AtomicIngeter的常用方法如下: 

    n int addAndGet(int delta): 以原子的方式将参数与实例中的值相加,并返回结果。 

    n boolean compareAndSet(int expect, int update): 如果输入的值等于预期值,则以原子方式将该值设置为输入的值。 

    n int getAndIncrement(): 以原子的方式将当前值加1,然后返回自增前的值,也就是旧值。此方法也是比较常用的方法,可以用来做计数器。 

    n void lazySet(int newValue): 最终会设置成newValue,使用lazySet设置值后,可能导致其他线程在之后的一小段时间内还是可以读到旧的值。 

    n int getAndSet(int newValue): 以原子的方式设置为newValue,并返回旧值。

    n int incrementAndGet(): 和getAndIncrement一样,他返回的是自增后的值。

    记得在讲解CAS应用的代码案例中,使用过原子自增的方法,下面我们看看getAndIncrement() 是如何实现原子操作的,请看2-45示例代码中AtomicInteger部分源码。

     

    代码清单2-45 AtomicInteger.java

     public final int getAndIncrement() {
            return unsafe.getAndAddInt(this, valueOffset, 1);
        }
    
    
    public final int getAndAddInt(Object var1, long var2, int var4) {
            int var5;
            do {
                var5 = this.getIntVolatile(var1, var2);
            } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
    
    
            return var5;
        }
    

    我们取得了旧值,然后把要加的数传过去,调用getAndAddInt () 进行原子更新操作,实际最核心的方法是 compareAndSwapInt(),使用CAS进行更新。我们Unsafe只提供了3中CAS操作,另外注意,AtomicBoolean 是把Boolean转成整型,在使用 compareAndSwapInt 进行操作的。在atomic包里的对象基本都是使用Unsafe提供的3中CAS操作的方法实现的,请看Unsafe源码,如代码清单2-46所示。

    代码清单2-46 Unsafe.java

    /**
     * 如果当前数值是var4,则原子的将java变量更新成var5或var6
     * @return 如果更新成功返回true
     */
    public final native boolean compareAndSwapObject(Object var1, long var2, Object var4, Object var5);
    
    
        public final native boolean compareAndSwapInt(Object var1, long var2, int var4, int var5);
    
    
        public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
    

     

    2.10.2原子更新数组

    l AtomicIntegerArray:  原子更新整型数组里的元素。

    l AtomicLongArray:  原子更新长整型数组里的元素。

    l AtomicReferenceArray:  原子更新引用类型数组里的元素。

     

    这三个类的最常用的方法是如下两个方法:

    n get(int index):获取索引为index的元素值。

    n compareAndSet(int i, int expect, int update): 如果当前值等于预期值,则以原子方式将数组位置 i 的元素设置为update值。

     

    2.10.3原子更新引用类型

     

    l AtomicReference:  原子更新引用类型。 

    l AtomicReferenceFieldUpdater:  原子更新引用类型的字段。 

    l AtomicMarkableReferce:  原子更新带有标记位的引用类型,可以使用构造方法更新一个布尔类型的标记位和引用类型。 

     

    这三个类提供的方法都差不多,首先构造一个引用对象,然后把引用对象set进Atomic类,然后调用compareAndSet等一些方法去进行原子操作,原理都是基于Unsafe实现,但AtomicReferenceFieldUpdater略有不同,更新的字段必须用volatile修饰。下面我们使用原子引用类型写一个简单的Demo,请看示例代码2-47所示

    代码清单2-47 AtomicReferenceDemo.java

    public class AtomicReferenceDemo {
        public static AtomicReference<User> ai = new AtomicReference<User>();
    
    
        public static void main(String[] args) {
    
    
            User u1 = new User("pangHu", 18);
            ai.set(u1);
            User u2 = new User("pangPang", 15);
            ai.compareAndSet(u1, u2);
            System.out.println(ai.get().getAge() + ai.get().getName());
        }
    
    
        static class User {
            private String name;
            private int age;
     //省略getter、settrt
        }
    }
    

    输出结果。

    15pangPang

     

    2.10.4原子更新字段类

    如果需要原子的更新类里某个字段时,需要用到原子更新字段类,Atomic包提供了3个类进行原子字段更新: 

     

    l AtomicIntegerFieldUpdater:  原子更新整型的字段的更新器。 

    l AtomicLongFieldUpdater:  原子更新长整型字段的更新器。 

    l AtomicStampedFieldUpdater:  原子更新带有版本号的引用类型。该方法比较重要,他和引用类型加上一个整数值,可以控制数据的版本号,这样就可以解决CAS更新时可能出现的ABA问题。和引用类型一样更新类的字段必须使用 public volatile 修饰。

     

    2.10.5 JDK8新增原子类简介

    l DoubleAccumulator

    l LongAccumulator

    l DoubleAdder

    l LongAdder

    下面以 LongAdder 为例介绍一下,并列出使用注意事项。

    这些类对应把 AtomicLong 等类的改进。比如 LongAccumulator 与 LongAdder 在高并发环境下比 AtomicLong 更高效。

    Atomic、Adder在低并发环境下,两者性能很相似。但在高并发环境下,Adder 有着明显更高的吞吐量,但是有着更高的空间复杂度。

    LongAdder其实是LongAccumulator的一个特例,调用LongAdder相当使用下面的方式调用LongAccumulator。

    sum()方法在没有并发的情况下调用,如果在并发情况下使用会存在计数不准,下面有代码为例。

    LongAdder不可以代替AtomicLong,虽然 LongAdder的add()方法可以原子性操作,但是并没有使用 Unsafe 的CAS算法,只是使用了CAS的思想。

    LongAdder其实是LongAccumulator的一个特例,调用LongAdder相当使用下面的方式调用LongAccumulator,LongAccumulator提供了比LongAdder更强大的功能,构造函数其中accumulatorFunction一个双目运算器接口,根据输入的两个参数返回一个计算值,identity则是LongAccumulator累加器的初始值。

    胖虎

    热 爱 生 活 的 人

    终 将 被 生 活 热 爱

    我在这里等你哟!

    展开全文
  • JUC–Atomic原子类

    2020-12-20 23:31:18
    原子类 java.util.concurrent.atomic包:原子类的小工具包,支持在单个变量上解除锁的线程安全编程 原子变量类相当于一种泛化的 volatile 变量,能够支持原子的和有条件的读-改-写操作。AtomicInteger 表示一个int...
  • 原子类的了解与使用

    2019-11-11 17:41:29
    原子类 一,什么是原子类 一度认为原子是不可再分割的最小单位,故原子类可以认为其操作都是不可分割。 二,为什么要有原子类 对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDK1.5之后,新增的原子...

    原子类

    一,什么是原子类

    一度认为原子是不可再分割的最小单位,故原子类可以认为其操作都是不可分割。

    二,为什么要有原子类

    对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDK1.5之后,新增的原子操作提供一种用法简单,性能高效,线程安全地更新一个变量的方式。这些类位于atomic包下,发展到JDK1.8,该包下共有17个类,囊括原子更新基本类型,原子更新属性,原子更新引用。
    在JDK1.8中新增的原子类为:DoubleAccumulator,DoubleAdder,LongAccumlator,LongAdder,striped64。

    三,原子更新基本类型

    大致可以分为三类:

    1,AtomicBoolean,AtomicInteger,AtomicLong:属于元老级的原子更新,方法几乎一样。
    2,DoubleAdder,LongAdder:对Double和long的原子更新性能进行优化提升。
    3,DoubleAccumulator,LongAccumulator:支持自定义运算

    AtomicInteger列子:

    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * AtomicInteger
     * 对sum进行自增操作
     */
    public class AtomicDemo {
    
        //相比较于 int sum = 0;
        private static AtomicInteger sum = new AtomicInteger(0);
    
        public static void increate(){
            sum.incrementAndGet();//相比较于sum++;
        }
    
        public static void main(String[] args) {
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    for (int j = 0; j < 10; j++) {
                        increate();
                        System.out.println(sum);
                    }
                }).start();
            }
        }
    }
    

    longAccumulator类型自定义运算列子:

    import java.util.concurrent.atomic.LongAccumulator;
    
    public class AtomicDemo2 {
        public static void main(String[] args) {
            LongAccumulator longAccumulator = new LongAccumulator((left,right)->
                    left*right,1
                    );
    
            longAccumulator.accumulate(3);
            System.out.println(longAccumulator.get());
        }
    }
    

    四, 原子更新数组类型

    分别有AtomicintegerArray, AtomicLongArray,AtomicReferenceArray
    AtomicintegerArray列子:

    /**
     * 原子AtomicIntegerArray数组更新
     */
    
    import java.util.concurrent.atomic.AtomicIntegerArray;
    
    public class AtomicDemo3 {
        public static void main(String[] args) {
            int[] array = {2,3};
            AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(array);
            System.out.println("atomicIntegerArray = " + atomicIntegerArray.addAndGet(1,2));
    
            //3+2+5 = 10
            int i = atomicIntegerArray.accumulateAndGet(1,5,(left, right) ->
                    left+right
                    );
            System.out.println("i = " + i);
        }
    }
    

    五,原子更新属性

    原子的更新某个类里的某个字段时,就需要使用更新字段类。atomic包下提供了以下四个类进行原子字段更新:
    AtomicIntegerFiledUpdater,AtomicLongFieldUpdater,AtomicStampedReference,AtomicReferenceFieldUpdater
    使用上述类的时候,必须遵循以下原则:
    1,属性字段必须是volatile类型,在线程之间共享变量时立即可见。
    2,字段的描述类型是与调用者与操作者对象字段的关系一致,也就是说调用者能够直接操作对象的字段,那么就可以进行原子类操作。
    3,对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
    4,只能是实例变量,不能是类变量,也就是说不能加static关键字修饰的,也不能是final修饰的变量。
    5,对于AtomicIntegerFiledUpdater,AtomicLongFieldUpdater只能修改int/long类型字段,不能是其包装类,如果要修改其包装类需要用另外的类。
    列子:
    student实体类

    public class Student {
        volatile long  id;
        volatile String name;
    
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Student(long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Student() {
        }
    }
    
    import java.util.concurrent.atomic.AtomicLongFieldUpdater;
    import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
    
    public class AtomicDemo4 {
        public static void main(String[] args) {
            //泛型填对应的实体类,参数为实体类的对象.class,与要修改的属性,且为字符串
            AtomicLongFieldUpdater<Student> atomicLongFieldUpdater =
                    AtomicLongFieldUpdater.newUpdater(Student.class,"id");
    
            Student student = new Student(1L,"Thomas");
            //比较然后替换,修改的属性为long类型id
            atomicLongFieldUpdater.compareAndSet(student,1L,100L);
            System.out.println("student = " + student.getId());
            
            AtomicReferenceFieldUpdater atomicReferenceFieldUpdater =
                    AtomicReferenceFieldUpdater.newUpdater(Student.class,String.class,"name");
            //修改的属性为String类型name
            atomicReferenceFieldUpdater.compareAndSet(student,"Thomas","Jack");
            System.out.println("student = " + student.getName());
        }
    }
    

    运行输出:
    实例化时的值为id:1 name:Thomas
    在这里插入图片描述

    六,原子更新引用

    AtomicReference:用于对引用的原子更新。
    AtomicMarkableReference:带版本戳的原子引用类型,版本戳为Boolean类型。
    AtomicStampedreference:带版本戳的原子引用类型,版本戳为int类型。

    AtomicReference更新引用类型列子:
    student实体类

    public class Student {
    
        private long id;
    
        private String name;
    
        public Student(long id, String name) {
            this.id = id;
            this.name = name;
        }
    
        public Student() {
        }
    
        public long getId() {
            return id;
        }
    
        public void setId(long id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    
    import java.util.concurrent.atomic.AtomicReference;
    
    public class AtomicDemo5 {
    
        public static void main(String[] args) {
            AtomicReference<Student> atomicReference = new AtomicReference();
            Student student1 = new Student(1L,"Thomas");
            Student student2 = new Student(2L,"Jack");
    		//不能直接将Thomas替换成Jack,需要经过以下步骤进行并获取
            atomicReference.set(student1);
            //把student1替换成student2
            atomicReference.compareAndSet(student1,student2);
            Student student = atomicReference.get();
            System.out.println(student.getName());
        }
    }
    
    

    运行结果:
    在这里插入图片描述

    展开全文
  • Java16个原子类介绍-基于JDK8

    万次阅读 2019-03-15 17:17:59
    emmmm,在写文章前我也翻阅了好多资料和书籍,其实大家在对原子类方法的使用介绍基本都没问题,但是对于java中原子类的个数是五花八门,下面我就把自己都认知和书籍资料结合起来给大家简单都介绍下java中原子类的...
  • 什么是css原子类The following is an extract from our book, CSS Master, written by Tiffany Brown. Copies are sold in stores worldwide, or you can buy it in ebook form here. 以下是蒂芙尼·布朗(Tiffany ...
  • Atomic原子类及原理

    千次阅读 2020-03-16 10:57:33
    一、引入 原子是世界上的最小单位,具有不可分割性。比如 a=0;...非原子操作都会存在线程安全问题,需要我们使用同步技术(sychronized)来让它变成一个原子操作。 但是,像i++这种非原子操...
  • Java中的原子类-并发编程

    千次阅读 2019-01-21 15:18:43
    1. 原子类是什么 原子类包装了一个变量,然后提供对这个变量的原子操作的方法。 注意:原子类中对变量的操作,都是原子操作。 2. 原子类有什么用 把变量的操作封装成原子操作,也就是保证了原子性。 多线程的三大...
  • Java原子类自增自减操作我们知道i++操作不是原子操作, 除了使用Synchronized进行同步外,也可以使用AtomicInteger/AtomicLong原子类进行实现。package com.wkcto.volatilekw;import java.util.concurrent.atomic....
  • 如果多线程中仅需要Atomic原子类解决的事情,就不需要synchronized重量级锁了。 原子类共四类: 基本类型:使用原子的方式更新基本类型   a. AtomicInteger整形原子类   b. AtomicLong长整型原子类   c. ...
  • JUC包中原子类使用及其原理

    千次阅读 2018-08-29 14:34:31
    我在详解JUC之原子类概述这篇文章中介绍了一下原子操作和JUC包下的原子类的类型,现在我就来介绍一下这些原子类。 操作基本类型的原子类 操作基本类型的原子类有3个 AtomicInteger:操作int...
  • Java原子类Atomic原理和应用

    千次阅读 2018-07-23 22:27:30
    jdk所提供的原子类可以大致分为四种类型: 原子更新基本数据类型 原子更新数组类型 原子更新抽象数据类型 原子更新字段   先来看看jdk提供的原子类(rt.jar包下java.util.concurrent.atomic):   首先我们...
  • 1、原子性概念 原子性是指**一个操作是不可中断的,要么全部执行成功,要么全部执行失败,有着“同生共死”的感觉。...List item 在java.util.concurrent.atomic包下定义了一些对“变量操作”的“原子类”,例:
  • 基本类型原子类

    千次阅读 2019-07-19 15:03:00
    AtomicInteger:整型原子类 AtomicLong:长整型原子类 AtomicBoolean :布尔型原子类 上面三个类提供的方法几乎相同,所以这里以 AtomicInteger 为例子来介绍。 AtomicInteger 类常用方法 public final int get(); ...
  • concurrent 的包结构共可分为五个部分: - 原子变量类 - 锁 - collection并发集合框架 - excutor线程池 ...以 AtomicInteger 为例,其它原子类的原理都一样: AtomicBoolean 可以用原子方式更新的 ...
  • Atomic 原子类

    2018-12-23 16:49:32
    Atomic原子类指具有原子性特征的类,所有的原子类API都在java.util.concurrent.atomic包下,如图所示: 使用原子类的作用就是不需要调用者手动加锁(volatile,synchronized等)就能保证在多线程环境中是线程安全...
  • 原子类AtomicInteger 在Java中,有很多方法可以保证多线程下数据的安全,AtomicXXXX这些类就是其中的一种,原子类,可以保证每一步操作都是原子操作。这次就对AtomicInteger的源码进行学习。 首先看一下这个类的类...
  • 方法有很多,比如:加锁、Atomic 原子类等。 好了,咱们今天先来看看Atomic类。 什么是 Atomic? Java从JDK1.5开始提供java.util.concurrent.atomic包,这里包含了多个原子操作类。原子操作类提供了一个简单、高效、...
  • Java多线程中的原子类主要有: 基本数据类型操作:AtomicInteger、AtomicLong、AtomicBoolean 数组操作:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray 对象的成员变量操作:...
  • 目录 1.什么是CAS? ---比较并交换(compare and swap) 1.1 AtomicInteger是什么...2.1 一句话解释:Unsafe和自旋锁 2.2Unsafe 2.3自旋锁 3.CAS的优缺点? 3.1CAS优点 3.2CAS缺点 4.CAS存在的问题 4.1...
  • Java原子类实现原理分析

    千次阅读 2018-03-16 13:43:34
    原子类来自于java.util.concurrent包,而java.util.concurrent包完全建立在CAS之上的,没有CAS就不会有此包。可见CAS的重要性。 什么是CAS Compare and Swap, 翻译成比较并交换。 java.util.concurrent包中借助...
  • AtomicInteger 原子类的作用 多线程操作,Synchronized 性能开销太大count++并不是原子操作。因为count++需要经过读取-修改-写入三个步骤。 count++并不是原子操作。因为count++需要经过读取-修改-写入三个步骤。...
  • AtomicLong是作用是对长整形进行原子操作。下面通过本文给大家介绍Java concurrency之AtomicLong原子类的相关知识,感兴趣的朋友一起看看吧
  • 根据修改的数据类型,可以将JUC包中的原子操作可以分为4种,分别是: 1.基本类型: AtomicInteger, AtomicLong, AtomicBoolean ;2.数组类型: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray ;3.引用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 278,179
精华内容 111,271
关键字:

原子类

友情链接: V15 PRJ protected.zip