简体   繁体   English

while循环并检查静态变量

[英]While loop and checking static variable

I have two threads and in one thread I set static variable and in another I check static variable via function like this 我有两个线程,在一个线程中我设置静态变量,在另一个线程中我通过这样的函数检查静态变量

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

But this codes hangs - doesn't go to println statement. 但这个代码挂起 - 不会去println声明。 But the following code works 但以下代码有效

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

The Temp class 临时班

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

Test class 考试班

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

What can be reason? 可能是什么原因? I set method isVarSet() synchronized but it didn't help. 我设置方法isVarSet()同步,但它没有帮助。
EDIT This code works too. 编辑此代码也有效。

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

You didn't publish what happens in Temp and isVarSet but most probably you change a variable. 你没有公布TempisVarSet发生的事情,但很可能你改变了一个变量。 This variable must be marked volatile . 此变量必须标记为volatile

If your class looks like this: 如果你的班级是这样的:

public class Temp {
   private static boolean someFlag;

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

And your loop is the same as the example, the compiler thinks that there's no need to read the flag over and over again because the flag is not changed inside the loop and it optimizes to not read the flag over and over. 并且你的循环与示例相同,编译器认为不需要一遍又一遍地读取标志,因为循环内的标志没有改变,并且它优化为不反复读取标志。

Marking someFlag as volatile : someFlag标记为volatile

private static volatile boolean someFlag;

Will force the runtime to check the flag on each iteration and not just assume that the value hasn't changed. 将强制运行时检查每次迭代的标志,而不仅仅是假设值没有更改。 In this case, it will work. 在这种情况下,它会工作。

From Oracle docs about atomic access : 来自Oracle有关原子访问的文档

Atomic actions cannot be interleaved, so they can be used without fear of thread interference. 原子动作不能交错,因此可以使用它们而不必担心线程干扰。 However, this does not eliminate all need to synchronize atomic actions, because memory consistency errors are still possible. 但是,这并不能消除所有同步原子操作的需要,因为仍然可能存在内存一致性错误。 Using volatile variables reduces the risk of memory consistency errors, because any write to a volatile variable establishes a happens-before relationship with subsequent reads of that same variable. 使用volatile变量可降低内存一致性错误的风险,因为对volatile变量的任何写入都会建立与之后读取同一变量的先发生关系。 This means that changes to a volatile variable are always visible to other threads. 这意味着对volatile变量的更改始终对其他线程可见。 What's more, it also means that when a thread reads a volatile variable, it sees not just the latest change to the volatile, but also the side effects of the code that led up the change. 更重要的是,它还意味着当线程读取volatile变量时,它不仅会看到volatile的最新更改,还会看到导致更改的代码的副作用。

  1. Even after you made variable as volatile . 即使你将变量变为volatile也是如此。
  2. if you add SOP in while loop it is working 如果你在while循环中添加SOP它正在工作

These two usecase gives me another thought. 这两个用例给了我另一个想法。 just try it. 去尝试一下。

Since your read and write methods are sync , in your while loop 由于您的读取和写入方法是同步的,因此在您的while循环中

while(!Temp.isVarSet()){
}

It is nothing doing other than calling the method, it may possible this sync method holds the lock on the Temp Object which does not allow other thread to modify the values (though sync setMethod) . 除了调用方法之外没什么可做的,可能这个同步方法保持Temp对象的锁定,这不允许其他线程修改值(虽然同步setMethod)。

While add SOP inside the while , it is doing some work on IO and thus it is allowing some time slice to other thread get the lock of Temp and modify the same. 虽然在内部添加SOP,但它正在对IO做一些工作,因此它允许一些时间片到其他线程获取Temp的锁并修改相同。

Could you please try remove Sync from read method , just for testing purpose and post your results. 您可以尝试从读取方法中删除同步,仅用于测试目的并发布结果。

public class Temp {

    private volatile static boolean varSet=false;

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

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

This works perfect for me: 这对我来说很完美:

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

}

Can you please post a complete example? 你能发一个完整的例子吗?

Its working as expected without hanging the program. 它按预期工作而不会挂起程序。

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