java并发编程基础--原子类与原子更新

一、原子类介绍

1、什么是原子类

原子类可以认为其操作都是不可分割

2、为什么要有原子类

对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后,新增的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,这些类同样位于JUC包下的atomic包下,

发展到JDk1.8,该包下共有17个类,囊括了原子更新基本类型、原子更新数组、原子更新属性、原子更新引用,其中,jdk1.8新增的原子类有DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

二、原子更新

1、原子更新基本类型

1)大致可以归为3类
      AtomicBoolean、AtomicInteger、AtomicLong  元老级的原子更新,方法几乎一模一样
      DoubleAdder、LongAdder  对Double、Long的原子更新性能进行优化提升
       DoubleAccumulator、LongAccumulator  支持自定义运算

2)示例

/**
 * LongAccumulator Demo
 */
public class Demo2 {

    public static void main(String[] args) {
        //输入一个数字,如果比上一个输入的大,则直接返回,如果小,则返回上一个
        LongAccumulator longAccumulator = new LongAccumulator((left, right) ->
                left * right, 0L
        );

        longAccumulator.accumulate(3L);
        System.out.println(longAccumulator.get());
        longAccumulator.accumulate(5L);
        System.out.println(longAccumulator.get());
    }

}

2、原子更新数组类型

1)类型:AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

2)示例:

/**
 * AtomicIntegerArray Demo
 */
public class AtomicIntegerArrayDemo {

    public static void main(String[] args) {
        int[] arr = new int[]{3, 2};
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
        System.out.println(atomicIntegerArray.addAndGet(1, 8));

        int i = atomicIntegerArray.accumulateAndGet(0, 2, (left, right) ->
                left * right / 3
        );


        System.out.println(i);
    }

}

3、原子更新属性

1)类型:AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater

2)使用上述类的时候,必须遵循以下原则
        字段必须是volatile类型的,在线程之间共享变量时保证立即可见
        字段的描述类型是与调用者与操作对象字段的关系一致。也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作。
        对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段。
        只能是实例变量,不能是类变量,也就是说不能加static关键字。
        只能是可修改变量,不能使final变量,因为final的语义就是不可修改。
        对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装类型(Integer/Long)。
        如果要修改包装类型就需要使用AtomicReferenceFieldUpdater。

3)示例:修改Student类中xuhan的字段

/**
 * AtomicLongFieldUpdaterDemo
 */
public class AtomicLongFieldUpdaterDemo {

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

        Student xuhan = new Student(1L, "xuhan1");
        longFieldUpdater.compareAndSet(xuhan, 1L, 100L);
        System.out.println("id="+xuhan.getId());

        AtomicReferenceFieldUpdater<Student, String> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");
        referenceFieldUpdater.compareAndSet(xuhan, "虚汗", "小旭");
        System.out.println("name="+xuhan.getName());
    }
}

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、 原子更新引用
1)类型:AtomicReference:用于对引用的原子更新
        AtomicMarkableReference:带版本戳的原子引用类型,版本戳为boolean类型。
        AtomicStampedReference:带版本戳的原子引用类型,版本戳为int类型。

2)示例:Student类与上面的一致

/**
 * AtomicReferenceDemo
 */
public class AtomicReferenceDemo {

    public static void main(String[] args) {
        AtomicReference<Student> studentAtomicReference = new AtomicReference<>();
        Student student = new Student(1L, "虚汗");
        Student student1 = new Student(2L, "小旭");
        studentAtomicReference.set(student);
        studentAtomicReference.compareAndSet(student, student1);
        Student student2 = studentAtomicReference.get();
        System.out.println(student2.getName());
    }
}

猜你喜欢

转载自blog.csdn.net/qq_38966361/article/details/87927101