原理
大佬的讲解,基础知识还是蛮清楚的,但是对原子性那块讲的不是很透彻:
深入理解Java内存模型
可见性
在多处理器下,为了保证各个处理器的缓存是一致的,就会实现缓存一致性协议,每个处理器通过嗅探在总线上传播的数据来检查自己缓存的值是不是过期了,当处理器发现自己缓存行对应的内存地址被修改,就会将当前处理器的缓存行设置成无效状态,当处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。
实例
package com.pcy.concurrent;
public class VolatileVisibility {
public static volatile boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("wait data...");
while (!initFlag){
}
System.out.println("==============>success");
}
}).start();
Thread.sleep(2000);
new Thread(new Runnable() {
@Override
public void run() {
prepareData();
}
}).start();
}
private static void prepareData() {
System.out.println("preparing data...");
initFlag = true;
System.out.println("preparing data end...");
}
}
原子性
实例:
package com.pcy.concurrent;
/**
* 在increase方法前不加synchronized,则可能会导致最终的结果 <= 10000,
* 原因是:同时read和use一个数据后,其中一个线程assign快了storage和write后改了主内存的值,
* 另一个线程获知后使工作内存的值失效了,但对于它来说只是赋值操作,并不会再次读取,所以这一步并不会去刷新主存,因此就丢失了这一次++操作
* ===> 这就是虽然read等使原子性的,但线程的执行过程取不是原子性的
*/
public class VolatileAtomic {
public static volatile int num = 0;
public static void increase(){
num++;
}
public static void main(String[] args) throws InterruptedException {
Thread[] threads = new Thread[10];
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run() {
for (int j = 0; j < 1000; j++) {
increase();
}
}
});
threads[i].start();
}
for (Thread thread : threads) {
thread.join();
}
System.out.println(num);
}
}