原子类——AtomicInteger原理分析
本节主要讲解Atomic打头的原子类的使用和原理。
原子操作
原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程上下文切换。
原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分,将整个操作视作一个整体是原子性的核心特征。
原子类
在java中提供了很多原子类,主要把这些原子类分成四大类。
原子更新基本类型或引用类型
- AtomicBoolean
原子更新布尔类型,内部使用int类型的value存储1和0表示true和false,底层也是对int类型的原子操作。
- AtomicInteger
原子更新int类型。
- AtomicLong
原子更新long类型。
- AtomicReference
原子更新引用类型,通过泛型指定要操作的类。
- AtomicMarkableReference
原子更新引用类型,内部使用Pair承载引用对象及是否被更新过的标记,避免了ABA问题。
- AtomicStampedReference
原子更新引用类型,内部使用Pair承载引用对象及更新的邮戳,避免了ABA问题。
原子更新数组中的元素
原子更新数组中的元素,可以更新数组中指定索引位置的元素,这些类主要有:
- AtomicIntegerArray
原子更新int数组中的元素。
- AtomicLongArray
原子更新long数组中的元素。
- AtomicReferenceArray
原子更新Object数组中的元素。
原子更新对象中的字段
原子更新对象中的字段,可以更新对象中指定字段名称的字段,这些类主要有:
- AtomicIntegerFieldUpdater
原子更新对象中的int类型字段。
- AtomicLongFieldUpdater
原子更新对象中的long类型字段。
- AtomicReferenceFieldUpdater
原子更新对象中的引用类型字段。
高性能原子类
高性能原子类,是java8中增加的原子类,它们使用分段的思想,把不同的线程hash到不同的段上去更新,最后再把这些段的值相加得到最终的值,这些类主要有:
- Striped64
下面四个类的父类。
- LongAccumulator
long类型的聚合器,需要传入一个long类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
- LongAdder
long类型的累加器,LongAccumulator的特例,只能用来计算加法,且从0开始计算。
- DoubleAccumulator
double类型的聚合器,需要传入一个double类型的二元操作,可以用来计算各种聚合操作,包括加乘等。
- DoubleAdder
double类型的累加器,DoubleAccumulator的特例,只能用来计算加法,且从0开始计算。
原子类常见面试题
2020年开年疫情的原因,讲到这里正值金三银四的时间,故给各位同学准备了常见面试题。
关于原子类的问题,无双老师整理了大概有以下这些:
(1)Unsafe是什么?
(3)Unsafe为什么是不安全的?
(4)Unsafe的实例怎么获取?
(5)Unsafe的CAS操作?
(6)Unsafe的阻塞/唤醒操作?
(7)Unsafe实例化一个类?
(8)实例化类的六种方式?
(9)原子操作是什么?
(10)原子操作与数据库ACID中A的关系?
(11)AtomicInteger怎么实现原子操作的?
(12)AtomicInteger主要解决了什么问题?
(13)AtomicInteger有哪些缺点?
(14)ABA是什么?
(15)ABA的危害?
(16)ABA的解决方法?
(17)AtomicStampedReference是怎么解决ABA的?
(18)实际工作中遇到过ABA问题吗?
(19)CPU的缓存架构是怎样的?
(20)CPU的缓存行是什么?
(21)内存屏障又是什么?
(22)伪共享是什么原因导致的?
(23)怎么避免伪共享?
(24)消除伪共享在java中的应用?
(25)LongAdder的实现方式?
(26)LongAdder是怎么消除伪共享的?
(27)LongAdder与AtomicLong的性能对比?
(28)LongAdder中的cells数组是无限扩容的吗?
AtomicInteger使用
package com.example.atomic.atomicinteger.demo;import java.util.concurrent.atomic.AtomicInteger;
/**
* @Author: 无双老师【云析学院:http://yunxiedu.net QQ:3190976240 email:zhouguanya20@163.com】
* @Date: 2020-03-21 16:20
* @Description: AtomicInteger使用方式
*/
public class AtomicIntegerDemo {
public static void main(String[] args) throws InterruptedException {
test1();
test2();
}
private static void test1() throws InterruptedException {
Counter counter = new Counter();
// 100个线程
for (int i = 0; i < 10; i++) {
// 每个线程对count累加10次
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
counter.addCount();
}
}).start();
}
Thread.sleep(1000);
System.out.println("count = " + counter.getCount());
}
private static void test2() throws InterruptedException {
/**
* 原子性的int
*/
AtomicInteger count = new AtomicInteger();
// 100个线程
for (int i = 0; i < 10; i++) {
// 每个线程对count累加10次
new Thread(() -> {
for (int j = 0; j < 1000; j++) {
count.incrementAndGet();
}
}).start();
}
Thread.sleep(1000);
System.out.println("count = " + count.get());
}
}
/**
* volatile修饰的计数器
*/
private volatile static int count = 0;
public void addCount() {
count++;
}
public int getCount() {
return count;
}
AtomicInteger原理
AtomicInteger声明
public class AtomicInteger extends Number implements java.io.Serializable
Unsafe类的使用
// setup to use Unsafe.compareAndSwapInt for updatesprivate static final Unsafe unsafe = Unsafe.getUnsafe();
private static final long valueOffset;
static {
try {
valueOffset = unsafe.objectFieldOffset
(AtomicInteger.class.getDeclaredField("value"));
} catch (Exception ex) { throw new Error(ex); }
}
AtomicInteger属性
private volatile int value;
AtomicInteger构造器
/** * Creates a new AtomicInteger with the given initial value.
*
* @param initialValue the initial value
*/
public AtomicInteger(int initialValue) {
value = initialValue;
}
/**
* Creates a new AtomicInteger with initial value {@code 0}.
*/
public AtomicInteger() {
}
AtomicInteger自增
/** * Atomically increments by one the current value.
*
* @return the updated value
*/
public final int incrementAndGet() {
return unsafe.getAndAddInt(this, valueOffset, 1) + 1;
}
调用Unsafe类的方法如下。
public final int getAndAddInt(Object var1, long var2, int var4) { int var5;
do {
var5 = this.getIntVolatile(var1, var2);
} while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));
return var5;
}
注意观察compareAndSwapInt即CAS方式修改int值。
AtomicInteger.incrementAndGet方法自增的原理:
- 调用unsafe.getAndAddInt方法
- unsafe.getAndAddInt方法通过自旋的方式,每次尝试通过CAS方法对原值进行累加。如果累加失败,将进入下一次循环。如果累加成功,则自旋结束。
以上是 原子类——AtomicInteger原理分析 的全部内容, 来源链接: utcz.com/z/514626.html