Java原子类
什么是原子类
- 一度认为原子是不可分割的最小单位,故原子类可以认为其操作都是不可分割
为什么要有原子类
- 对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,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 支持自定义运算
- AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样
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;
}
}