[英]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.