while循环并检查静态变量

时间:2014-05-04 14:30:45

标签: java multithreading

我有两个线程,在一个线程中我设置静态变量,在另一个线程中我通过这样的函数检查静态变量

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");

Temp类

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);
}

4 个答案:

答案 0 :(得分:4)

您没有发布TempisVarSet中发生的情况,但很可能是您更改了变量。此变量必须标记为volatile

如果您的课程如下:

public class Temp {
   private static boolean someFlag;

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

你的循环与示例相同,编译器认为不需要反复读取标志,因为循环内的标志没有改变,并且它优化为不反复读取标志。 / p>

someFlag标记为volatile

private static volatile boolean someFlag;

将强制运行时检查每次迭代时的标志,而不是仅仅假设该值未更改。在这种情况下,它会起作用。

来自Oracle docs about atomic access

  

原子动作不能交错,因此可以毫无顾虑地使用它们   线程干扰。但是,这并不能消除所有需要   同步原子操作,因为内存一致性错误   还有可能。使用volatile变量可降低内存风险   一致性错误,因为任何写入volatile变量   建立与之后发生的关系   同一个变量。这意味着对volatile变量的更改是   其他线程始终可见。更重要的是,它也意味着什么时候   一个线程读取一个volatile变量,它不仅看到最新的变化   对于挥发性,还有导致代码的副作用   变化

答案 1 :(得分:2)

  1. 即使你将变量变为易失性。
  2. 如果你在while循环中添加SOP它正在工作
  3. 这两个用例给了我另一个想法。试试吧。

    由于您的读写方法是同步的,因此在您的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;
        }
    }
    

答案 2 :(得分:1)

这对我来说非常适合:

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;
        }
    }

}

你能发一个完整的例子吗?

答案 3 :(得分:1)

它按预期工作而不会挂起程序。

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();
        }
    });
}