并发编程中的原子类

1.什么是原子类

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

1.1 为什么要有原子类?

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

1.2 1.8新增的原子类

DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

2.原子更新基本类型

发展至JDk1.8,基本类型原子类有以下几个:
AtomicBoolean、AtomicInteger、AtomicLong、DoubleAccumulator、DoubleAdder、LongAccumulator、
LongAdder
大致可以归为3类
AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样 DoubleAdder、
LongAdder 对Double、Long的原子更新性能进行优化提升 DoubleAccumulator、LongAccumulator 支持自定
义运算

/**
 * atomicInteger Demo
 */
public class Demo1 {

    private static AtomicInteger sum = new AtomicInteger(0);

    public static void inCreate() {

        sum.incrementAndGet();


    }


    public static void main(String[] args) throws InterruptedException {


        for (int i = 0; i < 10; i++) {
            new Thread(()->{

                for (int j = 0; j < 100; j++) {
                    inCreate();
                    System.out.println(sum);
                }
            }).start();

        }

    }
}
LongAccumulator Demo自定义运算
/**
 * LongAccumulator Demo
 * 自定义运算
 */
public class Demo2 {


    public static void main(String[] args) {

        //输入一个数字,如果比上一个输入的大,则直接返回
        //如果小则返回上一个
        LongAccumulator longAccumulator =
                new LongAccumulator((left, right) ->

//                    left > right ? left : right,
                    left+right ,
                        0L
                );
        longAccumulator.accumulate(3L);
        System.out.println(longAccumulator.get());
        longAccumulator.accumulate(5L);
        System.out.println(longAccumulator.get());
    }
}

3.原子更新数组类型

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

/**
 * AtomicIntegerArry  Demo
 */
public class AtomicIntegerArryDemo {

    public static void main(String[] args) {

        int[] arr = new int[]{3, 2};

        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);

        //下标和步长
        int i = atomicIntegerArray.addAndGet(1, 8);
        int j = atomicIntegerArray.addAndGet(0, 8);

        System.out.println("i:" + i + "--j:" + j);

        System.out.println(  atomicIntegerArray.toString());

        //自定义运算
        /**
         *下标
         * 把下标的值更新为20
         * 相关的运算
         */
        int k = atomicIntegerArray.accumulateAndGet(
                0, 20, (left, right) ->
                        left >right?left:right
        );
        System.out.println(  atomicIntegerArray.toString());
        System.out.println("k->"+k);

    }
}

4.原子地更新属性

原子地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下4个类进行原子字段更新
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater

/**
 * AtomicLongFieldUpdateDemo
 */
public class AtomicLongFieldUpdaterDemo {

    static 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;
        }
    }


    public static void main(String[] args) {
        AtomicLongFieldUpdater<Student> longFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");

        Student testStu = new Student(1L, "test");
        longFieldUpdater.compareAndSet(testStu, 1L, 100L);

        System.out.println("id=" + testStu.getId());

        AtomicReferenceFieldUpdater<Student, String> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");

        referenceFieldUpdater.compareAndSet(testStu, "test", "update");
        System.out.println("name=" + testStu.getName());

    }

}

5.原子更新引用

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

public class AtomicReferenceDemo {

    public static void main(String[] args) {
        AtomicReference<Student> studentAtomicReference = new AtomicReference<>();

        Student stuTest01 = new Student(1L, "test01");
        Student stuTest02 = new Student(2L, "test02");
        //先设置值
        studentAtomicReference.set(stuTest01);
        studentAtomicReference.compareAndSet(stuTest01,stuTest02);
        //再得到更新值
        Student studentUpd = studentAtomicReference.get();
        System.out.println(studentUpd.getName());


    }


}

class Student{

    private long id;
    private 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;
    }
}
posted @ 2019-05-19 19:58  城南少年与猫  阅读(511)  评论(0编辑  收藏  举报