while循環修改條件後沒法跳出的疑惑(已解決)

最近在編寫項目的時候使用while遇到了一個奇怪的問題。我在使用異步調用的時候主線程某一個方法須要等待異步返回才能被調用,所以我設定了一個boolean,當異步返回時修改條件而後在主線程的方法中加入while來長時間遍歷以等待異步返回。java

這裏我將代碼省略只保留主要:異步

public static void main(String[] args) {
    Task task = new Task();
    new Thread(task).start();
    try {
        Thread.sleep(3000);
    } catch (Exception e) {}
    task.close();
}

class Task implements Runnable {

    private int i = 1;
    
    public void run() {
        while (i == 1){}
        System.out.println("跳出循環");
    }
    
    public void close() {
        i = 2;
    }
}
複製代碼

Task啓動後會在while中死循環,主線程等待3s後將i修改爲2,可是task中的while沒有跳出,即 i == 1 條件仍是爲true。spa

其中的while換成for,do-while都是同樣的結果線程

經過詢問他人,雖然沒有弄明白髮生的緣由。可是他提出了一個解決辦法。code

在程序中內存

while(i == 1){}
複製代碼

會過多佔用CPU,所以使用Thread.yield()來將CPU資源讓步給其餘線程。當while中加入這個以後就能達到我須要的效果了。資源

很奇怪

更新: Java內存模型規定:同步

  1. 共享變量必須保存在主內存中
  2. 線程有本身的工做內存,線程只能夠操做本身的工做內存
  3. 線程要操做共享變量,須要從主內存中讀取到工做內存,修改後需從工做內存同步到主內存中。

這三點直接就點名了錯誤的緣由。解決辦法有兩個:string

  1. volatile關鍵字:
    volatile語意:it

    • 使用volatile變量時,必須從新從主內存加載,並read、load是連續的。
    • 修改volatile變量後,必須立馬同步回主內存,而且store、write是連續的。

    缺點:volatile只能保證線程的變量可見性。可是它沒有鎖機制,因此沒法避免多個線程同時訪問公共變量。

    優勢:編寫簡單。

  2. synchronized關鍵字
    synchronized語意:

    • 進入同步塊前,先清空工做內存的共享變量,再從主內存從新加載,同時獲取該共享資源的鎖。
    • 修改後必須先將共享變量同步回主內存中才能釋放鎖。

    優勢:有加鎖機制,保護共享資源。

補充 - 內存協議:

Java內存協議規定了8中原子操做:

  1. lock(鎖定):將主內存的變量鎖定,爲一線個線程獨佔。
  2. unlock(解鎖):將lock加的鎖解除。
  3. read(讀取):做用於主內存變量,將主內存的變量放入寄存器中。
  4. load(載入):做用於工做內存,將寄存器中的主內存變量傳遞給線程的工做內存。
  5. use(使用):做用於工做內存,將值傳遞給線程的代碼執行引擎。
  6. assign(賦值):做用於工做內存,將執行引擎處理返回的值從新賦值給寄存器。
  7. store(存入):將寄存器中的變量傳入主內存中。
  8. write(寫入):做用於主內存變量,將store傳過來的值寫入到主內存的共享變量中。

這些操做都是原子性,可是操做之間不是原子性。

相關文章
相關標籤/搜索