Java多线程中的原子类属性说明

 更新时间:2023年10月24日 08:53:33   作者:ruan_luqingnian  
这篇文章主要介绍了Java多线程中的原子类属性说明,对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后,新增的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,需要的朋友可以参考下

什么是原子类

什么是原子类

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

为什么要有原子类

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

java8新增原子类

DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64

package 多线程.atomic.demo1;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @Author: ruan
 * Date: 2021/7/4 12:09
 * @Description:
 */
public class Demo1 {
    private static AtomicInteger sum = new AtomicInteger(0);

    public static void inCreat(){
        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++) {
                    inCreat();
                    System.out.println(sum);
                    try {
                        Thread.sleep(200l);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        }
    }
}

原子更新基本类型

发展至JDk1.8,基本类型原子类有以下几个:

AtomicBoolean、AtomicInteger、AtomicLong、DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder

大致可以归为3类

  • AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样
  • DoubleAdder、LongAdder 对Double、Long的原子更新性能进行优化提升
  • DoubleAccumulator、LongAccumulator 支持自定义运算
package 多线程.atomic.demo1;

import java.util.concurrent.atomic.LongAccumulator;

/**
 * @Author: ruan
 * Date: 2021/7/4 12:20
 * @Description:
 */
public class Demo2 {
    public static void main(String[] args) {
        LongAccumulator longAccumulator = new LongAccumulator((left,right)->
                left > right ? left : right,0L
                );
        longAccumulator.accumulate(3l);
        System.out.println(longAccumulator.get());
    }
}

原子更新数组类型

AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray

package 多线程.atomic.demo2;

import java.util.concurrent.atomic.AtomicIntegerArray;

/**
 * @Author: ruan
 * Date: 2021/7/4 12:26
 * @Description:
 */
public class Demo1 {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
        int i = atomicIntegerArray.addAndGet(1, 2);
        System.out.println(i);
        //自定义计算
        int i1 = atomicIntegerArray.accumulateAndGet(0, 2, ((left, right) ->
                left > right ? left : right
        ));

        System.out.println(i1);
    }
}

原子更新属性

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

AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater

使用上述类的时候,必须遵循以下原则

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

import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;

/**
 * @Author: ruan
 * Date: 2021/7/4 12:48
 * @Description:
 */
public class Demo1 {
    public static void main(String[] args) {
        Student student = new Student("ruan", 18L);
        AtomicLongFieldUpdater<Student> longFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "age");
        longFieldUpdater.compareAndSet(student,18L,20L);
        System.out.println("age = " + student.getAge());
        AtomicReferenceFieldUpdater<Student, String> objectObjectAtomicReferenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class,String.class,"name");
        objectObjectAtomicReferenceFieldUpdater.compareAndSet(student,"ruan","ruanxiangge");
        System.out.println("name = " + student.getName());

    }
}
class Student{
    volatile String name;
    volatile long age;

    public Student(String name, long age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public long getAge() {
        return age;
    }

    public void setAge(long age) {
        this.age = age;
    }
}

原子更新引用

  • AtomicReference:用于对引用的原子更新
  • AtomicMarkableReference:带版本戳的原子引用类型,版本戳为boolean类型。
  • AtomicStampedReference:带版本戳的原子引用类型,版本戳为int类型。
package 多线程.atomic.demo4;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @Author: ruan
 * Date: 2021/7/4 13:03
 * @Description:
 */
public class Demo1 {
    public static void main(String[] args) {
        AtomicReference<Student> studentAtomicReference = new AtomicReference<>();
        Student ruan = new Student(1L, "ruan");
        Student rxg = new Student(2L, "rxg");
        studentAtomicReference.set(ruan );
        boolean b = studentAtomicReference.compareAndSet(ruan, rxg);
        Student student = studentAtomicReference.get();
        System.out.println(student.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;
    }
}

到此这篇关于Java多线程中的原子类属性说明的文章就介绍到这了,更多相关Java原子类属性内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

最新评论