1、什么是原子类
原子类可以认为其操作都是不可分割
2、为什么要有原子类
对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后,新增的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,这些类同样位于JUC包下的atomic包下,
发展到JDk1.8,该包下共有17个类,囊括了原子更新基本类型、原子更新数组、原子更新属性、原子更新引用,其中,jdk1.8新增的原子类有DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64
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());
}
}
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);
}
}
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 longFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");
Student xuhan = new Student(1L, "xuhan1");
longFieldUpdater.compareAndSet(xuhan, 1L, 100L);
System.out.println("id="+xuhan.getId());
AtomicReferenceFieldUpdater 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 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());
}
}