簡體   English   中英

while循環並檢查靜態變量

[英]While loop and checking static variable

我有兩個線程,在一個線程中我設置靜態變量,在另一個線程中我通過這樣的函數檢查靜態變量

Test test= new Test();
while(!Temp.isVarSet()){
}
System.out.println("Variable set");

但這個代碼掛起 - 不會去println聲明。 但以下代碼有效

Test test= new Test();
while(!Temp.isVarSet()){
  System.out.println("I am still here");
}
System.out.println("Variable set");

臨時班

public class Temp {

    private volatile static boolean varSet=false;

    public synchronized static void setVarSet() {
        Temp.varSet=true;
    }

    public synchronized static boolean isVarSet() {
        return Temp.varSet;
    }
}

考試班

public class Test{
        public Test() {
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    Model model= new Model();
                    View view = new View();
                    Controller controller=new Controller(model, view);
                    Temp.setVarSet();
                  ...
                }
            });
        }
    }

可能是什么原因? 我設置方法isVarSet()同步,但它沒有幫助。
編輯此代碼也有效。

Test test = Test()        
while(!Temp.isVarSet()){
            Thread.sleep(100);
}

你沒有公布TempisVarSet發生的事情,但很可能你改變了一個變量。 此變量必須標記為volatile

如果你的班級是這樣的:

public class Temp {
   private static boolean someFlag;

   public static boolean isVarSet() {
      return someFlag;
   }
}

並且你的循環與示例相同,編譯器認為不需要一遍又一遍地讀取標志,因為循環內的標志沒有改變,並且它優化為不反復讀取標志。

someFlag標記為volatile

private static volatile boolean someFlag;

將強制運行時檢查每次迭代的標志,而不僅僅是假設值沒有更改。 在這種情況下,它會工作。

來自Oracle有關原子訪問的文檔

原子動作不能交錯,因此可以使用它們而不必擔心線程干擾。 但是,這並不能消除所有同步原子操作的需要,因為仍然可能存在內存一致性錯誤。 使用volatile變量可降低內存一致性錯誤的風險,因為對volatile變量的任何寫入都會建立與之后讀取同一變量的先發生關系。 這意味着對volatile變量的更改始終對其他線程可見。 更重要的是,它還意味着當線程讀取volatile變量時,它不僅會看到volatile的最新更改,還會看到導致更改的代碼的副作用。

  1. 即使你將變量變為volatile也是如此。
  2. 如果你在while循環中添加SOP它正在工作

這兩個用例給了我另一個想法。 去嘗試一下。

由於您的讀取和寫入方法是同步的,因此在您的while循環中

while(!Temp.isVarSet()){
}

除了調用方法之外沒什么可做的,可能這個同步方法保持Temp對象的鎖定,這不允許其他線程修改值(雖然同步setMethod)。

雖然在內部添加SOP,但它正在對IO做一些工作,因此它允許一些時間片到其他線程獲取Temp的鎖並修改相同。

您可以嘗試從讀取方法中刪除同步,僅用於測試目的並發布結果。

public class Temp {

    private volatile static boolean varSet=false;

    public synchronized static void setVarSet() {
        Temp.varSet=true;
    }

    public  static boolean isVarSet() {
        return Temp.varSet;
    }
}

這對我來說很完美:

public class ThreadTest {

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

        Thread t1 = new TheThread();
        t1.start();

        // wait
        Thread.sleep(500);
        System.out.println(Thread.currentThread().getId() + " will now setVarSet()");
        Temp.setVarSet();
        System.out.println(Thread.currentThread().getId() + " setVarSet() setted");

        t1.join();
        System.out.println(Thread.currentThread().getId() + " end programm");

    }

    private static class TheThread extends Thread {

        @Override
        public void run() {

            System.out.println(Thread.currentThread().getId() + " enter run");

            while (!Temp.isVarSet()) {
                System.out.println(Thread.currentThread().getId() + " running");
                try {
                    Thread.sleep((int) (Math.random() * 100));
                } catch (InterruptedException e) {
                    // ignore
                }
            }

            System.out.println(Thread.currentThread().getId() + " exit run");
        }
    }

    private static class Temp {

        private volatile static boolean varSet = false;

        public static void setVarSet() {
            Temp.varSet = true;
        }

        public static boolean isVarSet() {
            return Temp.varSet;
        }
    }

}

你能發一個完整的例子嗎?

它按預期工作而不會掛起程序。

private volatile static boolean varSet = false;

public synchronized static void setVarSet() {
    varSet = true;
}

public synchronized static boolean isVarSet() {
    return varSet;
}

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

    Thread t1 = new Thread(new Runnable() {

        @Override
        public void run() {
            while (!TestDemo.isVarSet()) {
                // System.out.println("I am still here");
            }
            System.out.println("Variable set");

        }

    });
    t1.start();

    Thread.sleep(1000); // put delay to give the chance to execute above thread

    java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {
            // Model model= new Model();
            // View view = new View();
            // Controller controller=new Controller(model, view);
            setVarSet();
        }
    });
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM