最近网上看到一份题目,发现好多题目都是只有印象知道大概,具体深入的地方记不清了
volatile三大特性:
1. 保证可见性
2.不保证原子性
3.禁止指令重排
可见性:当一个线程修改了主内存(堆)中对象的值时,通知其他线程值已经修改
可见性验证:代码验证
import javax.swing.plaf.basic.BasicTreeUI;
import java.util.concurrent.TimeUnit;
/**
* @Author: chenoyongqiao
* @Description:
* @Date:Created in 8:10 2021/8/8
* @Modified By:
*/
public class VolatileDemo {
public static void main(String[] args) {
MyDate myDate = new MyDate();
new Thread(() -> {
while (myDate.runFlag) {
//当线程2修改了主内存中的runFlag,线程1也不会识到,循环不会停止
}
System.out.println(Thread.currentThread().getName() + "任务结束");
}, "线程1").start();
new Thread(() -> {
try {
System.out.println(Thread.currentThread().getName() + "进入");
//线程2休眠1秒保证线程1先拿到runFlag
TimeUnit.SECONDS.sleep(1);
// 线程操控资源类
myDate.runFlag = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "线程2").start();
//System.out.println("主线程结束");
}
}
class MyDate {
//增加volatile修改后runFlag具有可见性
volatile Boolean runFlag = true;
//Boolean runFlag = true;
Integer number = 0;
void addTo10() {
this.number = 10;
}
}
原子性:指一个操作要么完成,要么失败不能中断。
原子性代码验证:gitee代码验证
for (int i = 0; i < 100; i++) {
new Thread(()->{
myDate.addAndAdd();
},"验证原子性"+i).start();
}
System.out.println("验证原子性多次增加后值"+myDate.number);
}
}
class MyDate {
//增加volatile修改后runFlag具有可见性
volatile Boolean runFlag = true;
//Boolean runFlag = true;
volatile Integer number = 0;
// 使用原子类保证原子性
void addTo10() {
this.number = 10;
}
volatile不能保证原子性怎么处理?
使用原子类进行处理使用原子类解决volatile不能保证原子性的问题
volatile Integer number = 0;
// 使用原子类保证原子性
AtomicInteger atomicInteger = new AtomicInteger();
void addTo10() {
this.number = 10;
}
void addAndAdd(){
this.number++;
atomicInteger.getAndAdd(1);
}
原子类为什么可以保证原子性:
原子类调用jdk中rt.jar com.misc.Unsafe
/**
* Atomically adds the given value to the current value.
*
* @param delta the value to add
* @return the previous value
*/
public final int getAndAdd(int delta) {
return unsafe.getAndAddInt(this, valueOffset, delta);
}
3
传入三个参数,对象本身(预期值,从主内存中复制得到,后面会讲的)、值偏移量(对象的内存地址/指针)、add的入参。
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;
}
var5 = this.getIntVolatile(var1, var2);通过native拿到内存中的最新值,这个值为预期值
compareAndSwapInt(var1, var2, var5, var5 + var4));CAS思想,比较预期值与内存中的真实值,相等则将var5+var4更新到内存,否则更新var的值继续这个比较过程。