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