public class VolatileVisibilityTest{
private static boolean initFlag = false;
public static void main(String[] args) throws InterruptedException {
//线程1
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("waiting data...");
while (!initFlag){
}
System.out.println("======success");
}
}).start();
//确保线程1已经开始运行了,再运行线程2。
Thread.sleep(2000);
//线程2
new Thread(new Runnable() {
@Override
public void run() {
prepareData();
}
}).start();
}
private static void prepareData() {
System.out.println("prepareing data...");
initFlag = true;
System.out.println("prepare data end...");
}
}
initFlag
的值,线程2更改值为"true"后,线程1感知不到,并依旧使用自己工作内存中initFlag
的共享变量副本的值,因此无法结束while
循环。volatile
:保证共享变量再多线程之间的可见性。当其中一个线程更改了共享变量,其它线程可以马上感知并更新自己共享变量副本中共享变量的值。volatile
修饰即可:private static volatile boolean initFlag = false;
。原子操作都是硬件级别的实现。
volatile
修饰符:initFlag = false
。initFlag = false
写入线程1的工作内存中。initFlag = false
并取反),执行引擎执行while
循环的字节码指令(死循环)。initFlag = false
。initFlag = false
写入线程2的工作内存中。initFlag = false
要改成true
)。true
重新赋值到工作内存中(把initFlag = false
改成initFlag = true
)。initFlag = true
放写入主内存,但还没有写入共享变量initFlag
中。initFlag = true
,写入主内存里对应的共享变量中。initFlag = false
,继续死循环。volatile
底层的实现方式。-ser -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly -XX:CompileCommand=compileonly,*VolatileVisibilityTest.prepareData
volatile
保证可见性与有序性,但能不保证原子性,保证原子性需借助synchronized
这样的锁机制。volatile
不能保证原子性案例代码public class VolatileAtomicTest {
public static volatile int num = 0;
public static void increase() {
num++; //num = num+1
}
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 i = 0; i < 1000; i++) {
increase();
}
}
});
threads[i].start();
}
for (Thread t : threads) {
t.join();
}
System.out.println(num); //1000*10=10000
}
}
volatile
不能保证原子性案例代码 模型图volatile
不能保证原子性案例代码 执行流程num = 0
。num = 0
写入线程1的工作内存中。num++
字节码指令。num++
的值变为失效状态,线程2就浪费了一次num++
。num++
但num
的值为1,因线程2的作废。