[英]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);
}
你沒有公布Temp
和isVarSet
發生的事情,但很可能你改變了一個變量。 此變量必須標記為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的最新更改,還會看到導致更改的代碼的副作用。
這兩個用例給了我另一個想法。 去嘗試一下。
由於您的讀取和寫入方法是同步的,因此在您的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.