多线程的共享变量的内存不可见性如何理解

demo1

package com.entity;
  public class Test01 {
  private static boolean flag;

  public static void main(String[] args) throws InterruptedException {
  new Thread() {

  @Override
  public void run() {
    while(true){
      if (flag == !flag) {
      System.out.println("==over==");
      System.exit(0);
      }
    }
  }
}.start();
Thread.sleep(1);
new Thread() {

  @Override
  public void run() {
    while (true) {
      flag = !flag;
    }
  }
}.start();
}

}

该方式下运行 System.out.println("==over=="); 永远不会执行进入了死循环

public class Test02 {
private static volatile boolean flag;

public static void main(String[] args) throws InterruptedException {
new Thread() {

@Override
public void run() {
while(true){
if (flag == !flag) {
System.out.println("==over==");
System.exit(0);
}
}
}
}.start();
Thread.sleep(1);
new Thread() {

@Override
public void run() {
while (true) {
flag = !flag;
}
}
}.start();
}

}
该方式下运行 System.out.println("==over=="); 打印

demo2

public class Test03 {
private static boolean keepRunning=true;

public static void main(String[] args) throws Exception {

new Thread(
@override
public void run{
while (keepRunning){
//System.out.println("========");;
}
}

).start();

Thread.sleep(1000);
keepRunning=false;

}
}
同样 永远死循环

public class Test04 {
private static volatile keepRunning=true;

public static void main(String[] args) throws Exception {

new Thread(
@override
public void run{
while (keepRunning){
System.out.println("========");
}
}

).start();

Thread.sleep(1000);
keepRunning=false;

}
}
把注释打开 System.out.println("========"); 执行程序结束 怎么跟内存不可见对应不上呢?
参见:https://www.cnblogs.com/wenjieyatou/p/6210189.html 是由于 打印语句触发了happen—before


public class StopThread {
private static boolean stopRequested;

public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!isStopRequested()) {
i++;
}
}
});

backgroundThread.start();
TimeUnit.SECONDS.sleep(1);//1秒
requestStop();
}
}
此种情况下还是始终死循环 因为i++ 没有触发happen—before


出现死循环的原因:
java 内存模型(JMM)有主内存和线程的工作内存 关系如下:
1. 线程的工作内存会去读取主内存的成员变量并保存副本
2. 线程在工作内存中修改副本
3. 将修改后的副本的值推送给主空间并改写主空间该成员变量的值(线程栈执行完毕后会把副本的值推送给主存)
4. 主空间成员变量修改后的值将不会主动推送给其他线程, 这就造成了线程的工作内存的共享变量的不同步
就是造成上面死循环的原因

如何解决呢?
通过 volatile 解决
Volatile字段主要用于线程之间进行通信,volatile字段的每次读行为都能看到其它线程最后一次对该字段的写行为,所以共享变量的数据是最新的

参考文章:
http://www.cnblogs.com/huangleshu/p/10026222.html
https://baijiahao.baidu.com/s?id=1595082600371869908&wfr=spider&for=pc

static 是内存中的唯一份共享变量 volatile 也是内存唯一份的内存可见 那么二者有和区别呢?
1. volatile是告诉编译器,每次取这个变量的值都需要从主存中取,而不是用自己线程工作内存中的缓存.
2. static 是说这个变量,在主存中所有此类的实例用的是同一份,各个线程创建时需要从主存同一个位置拷贝到自己工作内存中去(而不是拷贝此类不同实例中的这个变量的值),
也就是说只能保证线程创建时,变量的值是相同来源的,运行时还是使用各自工作内存中的值,依然会有不同步的问题.

参考:http://www.cnblogs.com/cvbaka/p/4764503.html

原文地址:https://www.cnblogs.com/ljy-skill/p/10737552.html