多線程的共享變量的內存不可見性如何理解


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM