并发编程中的原子类
1.什么是原子类
一度认为原子是不可分割的最小单位,故原子类可以认为其操作都是不可分割
1.1 为什么要有原子类?
对多线程访问同一个变量,我们需要加锁,而锁是比较消耗性能的,JDk1.5之后, 新增的原子操作类提供了
一种用法简单、性能高效、线程安全地更新一个变量的方式, 这些类同样位于JUC包下的atomic包下,发展
到JDk1.8,该包下共有17个类, 囊括了原子更新基本类型、原子更新数组、原子更新属性、原子更新引用
1.2 1.8新增的原子类
DoubleAccumulator、DoubleAdder、LongAccumulator、LongAdder、Striped64
2.原子更新基本类型
发展至JDk1.8,基本类型原子类有以下几个:
AtomicBoolean、AtomicInteger、AtomicLong、DoubleAccumulator、DoubleAdder、LongAccumulator、
LongAdder
大致可以归为3类
AtomicBoolean、AtomicInteger、AtomicLong 元老级的原子更新,方法几乎一模一样 DoubleAdder、
LongAdder 对Double、Long的原子更新性能进行优化提升 DoubleAccumulator、LongAccumulator 支持自定
义运算
/**
* atomicInteger Demo
*/
public class Demo1 {
private static AtomicInteger sum = new AtomicInteger(0);
public static void inCreate() {
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++) {
inCreate();
System.out.println(sum);
}
}).start();
}
}
}
LongAccumulator Demo自定义运算
/**
* LongAccumulator Demo
* 自定义运算
*/
public class Demo2 {
public static void main(String[] args) {
//输入一个数字,如果比上一个输入的大,则直接返回
//如果小则返回上一个
LongAccumulator longAccumulator =
new LongAccumulator((left, right) ->
// left > right ? left : right,
left+right ,
0L
);
longAccumulator.accumulate(3L);
System.out.println(longAccumulator.get());
longAccumulator.accumulate(5L);
System.out.println(longAccumulator.get());
}
}
3.原子更新数组类型
AtomicIntegerArray、AtomicLongArray、AtomicReferenceArray
/**
* AtomicIntegerArry Demo
*/
public class AtomicIntegerArryDemo {
public static void main(String[] args) {
int[] arr = new int[]{3, 2};
AtomicIntegerArray atomicIntegerArray = new AtomicIntegerArray(arr);
//下标和步长
int i = atomicIntegerArray.addAndGet(1, 8);
int j = atomicIntegerArray.addAndGet(0, 8);
System.out.println("i:" + i + "--j:" + j);
System.out.println( atomicIntegerArray.toString());
//自定义运算
/**
*下标
* 把下标的值更新为20
* 相关的运算
*/
int k = atomicIntegerArray.accumulateAndGet(
0, 20, (left, right) ->
left >right?left:right
);
System.out.println( atomicIntegerArray.toString());
System.out.println("k->"+k);
}
}
4.原子地更新属性
原子地更新某个类里的某个字段时,就需要使用原子更新字段类,Atomic包提供了以下4个类进行原子字段更新
AtomicIntegerFieldUpdater、AtomicLongFieldUpdater、AtomicStampedReference、AtomicReferenceFieldUpdater
/**
* AtomicLongFieldUpdateDemo
*/
public class AtomicLongFieldUpdaterDemo {
static 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;
}
}
public static void main(String[] args) {
AtomicLongFieldUpdater<Student> longFieldUpdater = AtomicLongFieldUpdater.newUpdater(Student.class, "id");
Student testStu = new Student(1L, "test");
longFieldUpdater.compareAndSet(testStu, 1L, 100L);
System.out.println("id=" + testStu.getId());
AtomicReferenceFieldUpdater<Student, String> referenceFieldUpdater = AtomicReferenceFieldUpdater.newUpdater(Student.class, String.class, "name");
referenceFieldUpdater.compareAndSet(testStu, "test", "update");
System.out.println("name=" + testStu.getName());
}
}
5.原子更新引用
AtomicReference:用于对引用的原子更新
AtomicMarkableReference:带版本戳的原子引用类型,版本戳为boolean类型。
AtomicStampedReference:带版本戳的原子引用类型,版本戳为int类型。
public class AtomicReferenceDemo {
public static void main(String[] args) {
AtomicReference<Student> studentAtomicReference = new AtomicReference<>();
Student stuTest01 = new Student(1L, "test01");
Student stuTest02 = new Student(2L, "test02");
//先设置值
studentAtomicReference.set(stuTest01);
studentAtomicReference.compareAndSet(stuTest01,stuTest02);
//再得到更新值
Student studentUpd = studentAtomicReference.get();
System.out.println(studentUpd.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;
}
}