1、一度认为原子是不可分割的最小单位,故原子类可以认为其操作都是不可分割
2、对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后,新增的原子操作类提供了一种用法简单、性能高效、线程安全地更新一个变量的方式,这些类同样位于JUC包下的atomic包下,发展到JDk1.8,该包下共有17个类,囊括了原子更新基本类型、原子更新数组、原子更新属性、原子更新引用
3、1.8新增的原子类:DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64
1、发展至JDk1.8,基本类型原子类有以下几个:AtomicBoolean、AtomicInteger、AtomicLong、DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder
2、大致可以归为3类
AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样
DoubleAdder、LongAdder 对Double、Long的原子更新性能进行优化提升
DoubleAccumulator、LongAccumulator 支持自定义运算
public class Demo1 {
// 定义变量sum为0
private static AtomicInteger sum = new AtomicInteger(0);
public static void inCreate() {
sum.incrementAndGet(); // 自增
}
// 在不使用锁的情况下,创建多个线程,对同一个变量进行原子操作
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
for (int j = 0; j < 100; j++) {
inCreate();
System.out.println(sum);
}
}).start();
}
}
}
public class Demo2 {
public static void main(String[] args) {
//输入一个数字,如果比上一个输入的大,则直接返回,如果小,则返回上一个
LongAccumulator longAccumulator = new LongAccumulator((left, right) ->
left > right ? left : right, 0L
); // 第2个参数是初始值
longAccumulator.accumulate(3L);
System.out.println(longAccumulator.get());
longAccumulator.accumulate(5L);
System.out.println(longAccumulator.get());
}
}
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
public class AtomicIntegerArrayDemo {
public static void main(String[] args) {
// new 1个数组
int[] arr = new int[]{5, 3, 4};
// 将数组作为参数传入
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
// 索引下标1的值加8
System.out.println(atomicIntegerArray.addAndGet(2, 8));
// 索引下标0的值作为left,2作为right
int i = atomicIntegerArray.accumulateAndGet(0, 2, (left, right) ->
left * right
);
System.out.println(i);
}
}
1、原子地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下4个类进行原子字段更新
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater
2、使用上述类的时候,必须遵循以下原则
字段必须是volatile类型的,在线程之间共享变量时保证立即可见
字段的描述类型是与调用者与操作对象字段的关系一致。 也就是说调用者能够直接操作对象字段,那么就可以反射进行原子操作
对于父类的字段,子类是不能直接操作的,尽管子类可以访问父类的字段
只能是实例变量,不能是类变量,也就是说不能加static关键字
只能是可修改变量,不能使final变量,因为final的语义就是不可修改
对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型的字段,不能修改其包装 类型(Integer/Long)
如果要修改包装类型就需要使用AtomicReferenceFieldUpdater
public class AtomicLongFieldUpdaterDemo {
public static void main(String[] args) {
// 要修改的字段
AtomicLongFieldUpdater<Student> longFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");
Student xdclass = new Student(1L, "xdclass");
// 传入对象,expect表示期待的值,即是要修改的值,update表示修改后的值
longFieldUpdater.compareAndSet(xdclass, 1L, 100L);
System.out.println("id="+xdclass.getId());
// 要修改的字段
AtomicReferenceFieldUpdater<Student, String> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");
referenceFieldUpdater.compareAndSet(xdclass, "xdclass", "wiggin");
System.out.println("name="+xdclass.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;
}
}
AtomicReference:用于对引用的原子更新
AtomicMarkableReference:带版本戳的原子引用类型,版本戳为boolean类型
AtomicStampedReference:带版本戳的原子引用类型,版本戳为int类型
public class AtomicReferenceDemo {
// 将student更新为student1
public static void main(String[] args) {
AtomicReference<Student> studentAtomicReference = new AtomicReference<>();
Student student = new Student(1L, "xdclass");
Student student1 = new Student(2L, "wiggin");
studentAtomicReference.set(student);
studentAtomicReference.compareAndSet(student, student1);
Student student2 = studentAtomicReference.get();
System.out.println(student2.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;
}
}