繁体   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