目录
1、原子性
1.1 原子性的定义
原子性指一个操作是不可分割的,不可中断的,一个线程在执行时,另一个线程不会影响到他。
原子性:一个操作是不可分割的,要么一起成功,要么一起失败
1.2 volatile count++流程分析
- 从主内存获取数据到寄存器
- 在CPU内部执行+1 操作
- 将CPU寄存器数据写回到主内存
1.3如何保证原子性
1.3.1 synchronized
synchronized 可以避免让多线程同时操作临界资源,同一时间点,只会让一个线程去操作临界资源,
原理:
- 当线程操作资源时,先要获取锁资源(monitorenter),获取到锁资源后,才能进行后面的资源操作
- 当指令执行完毕,锁资源会释放(monitorexit),其他线程可以进行锁资源的获取
示例:
public class Atomicity {
public static int count;
public static void increment() {
synchronized (Atomicity.class) {
count++;
}
}
}
对代码进行编译查看
javac -encoding utf-8 .\Atomicity.java
javap -v .\Atomicity.class
1.3.2 CAS
cas: compare and swap也就是比较和交换,他是一条CPU的并发原语。
CAS 多线程操作临界资源
public class Atomicity {
private static AtomicInteger count = new AtomicInteger(0);
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
count.incrementAndGet();
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 100; i++) {
count.incrementAndGet();
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(count);
}
}
//200
CAS操作资源能够保证原子性,主要是他在替换内存的某个位置的值时,首先查看内存中的值与预期值是否一致,如果一致,执行替换操作。这个操作是一个原子性操作。
查看AtomicInteger源码
private static final Unsafe U = Unsafe.getUnsafe();
private static final long VALUE
= U.objectFieldOffset(AtomicInteger.class, "value");
private volatile int value;
incrementAndGet 借助了Unsafe类的 getAndAddInt()方法,可以看到,最终指向了一个native方法
public final int getAndAddInt(Object o, long offset, int delta) {
int v;
do {
v = getIntVolatile(o, offset);
} while (!weakCompareAndSetInt(o, offset, v, v + delta));
return v;
}
public native int getIntVolatile(Object o, long offset);
getIntVolatile 方法又两个参数,该方法的主要作用是:获取当前对象var1在该对象指定偏移量var2上的值
- var1:待计算的对象
- var2:在对象上的偏移量
除了这个方法,像Unsafe中的getIntVolatile、getBooleanVolatile、getByteVolatile、getShortVolatile、getCharVolatile、getLongVolatile、getFloatVolatile、getDoubleVolatile等方法都是类似的作用。
CAS的缺点:CAS只能保证对一个变量的操作是原子性的,无法实现对多行代码实现原子性。
ABA问题: