我正在学习易变量。我知道volatile的作用,我为Volatile变量编写了一个示例程序,但没有按预期工作。
为什么程序进入无限循环? 如果变量“isTrue”是volatile,那么它应该总是从主内存中获取值?线程为什么要缓存它?
有人可以解释一下原因吗?如果可以提供解决方案...(我不会将 isTrue 放入while循环)
我有一个VolatileSample类: -
public class VolatileSample{
static volatile boolean isTrue=true;
public VolatileSample(boolean is){
isTrue=is;
}
public void print() {
boolean b=isTrue;
while (b) {
System.out.println("In loop!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public void setFalse() {
boolean b=false;
System.out.println("Setting value as false");
isTrue=b;
}
}
创建了两个主题: -
public class Thread1 extends Thread{
VolatileSample sample;
public Thread1(VolatileSample sample){
this.sample=sample;
}
public void run(){
sample.print();
}
} 和
public class Thread2 extends Thread{
VolatileSample sample;
public Thread2(VolatileSample sample){
this.sample=sample;
}
public void run(){
sample.setFalse();
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
主要课程: -
public class Test {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
VolatileSample sample=new VolatileSample(true);
Thread1 t1=new Thread1(sample);
Thread2 t2=new Thread2(sample);
t1.start();
t2.start();
}
}
答案 0 :(得分:4)
当您使用while(b)
时,您在print
方法中使用while(isTrue)
。 b
是一个未更新的局部变量,而isTrue
是可以在外部更新的volatile变量。这应该有效:
//using this you will understand meaning of volatile
while (isTrue) {
System.out.println("In loop!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
请注意Java is pass by value, not by reference。更新isTrue
字段的值不会直接更新b
方法中print
本地参数的值。如果您不想使用while(isTrue)
(非常奇怪),那么只需在循环中更新b
的值:
while (b) {
System.out.println("In loop!");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//you need to use the volatile variable in order to understand volatile
b = isTrue;
}
请注意,如果您从未将isTrue
更新为false
,则循环将是无限的。让main
方法在天真延迟后更新字段:
public class Test {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
VolatileSample sample=new VolatileSample(true);
Thread1 t1=new Thread1(sample);
Thread2 t2=new Thread2(sample);
t1.start();
t2.start();
//naive delay
Thread.sleep(2500);
sample.setFalse();
}
}
您说您不想在isTrue
循环中使用while
变量。然后,在获取其值后,您无法在b
方法内更新print
变量。由于此代码中的b
将为true
,因此您将拥有无限循环。周期。
似乎您希望通过两个线程同步此类,但这不是volatile
字段的重点,因为您对方法或代码段使用synchronized
修饰符,如@JigarJoshi指出。通过阅读Simplest and understandable example of volatile keyword in java
答案 1 :(得分:1)
您实际上是将false
设置为本地变量
public void setFalse() {
boolean b=false; // <-- this is local variable
System.out.println("Setting value as false");
isTrue=b; // <-- this is shared but you don't check on it in your while loop
}
不是共享的
您可能希望通过选中isTrue
答案 2 :(得分:0)
@LuiggiMendoza是对的:在学习语言的基本功能(例如方法调用如何工作)之前,不应该尝试理解volatile
。
但是如果你坚持......尝试运行它,然后在从volatile
声明中取出timeToStop
关键字后再试一次。我无法保证您的操作系统上的JVM会发生什么; Java语言规范不保证当您不说volatile
时会发生什么。但是,在我的操作系统上的JVM中,如果变量不是volatile
,程序永远不会终止。
class Foo {
private static volatile boolean timeToStop = false;
private static long count = 0;
public static void main(String[] argsIgnored) throws InterruptedException {
Thread busyThread = new Thread(new Runnable() {
@Override
public void run() {
while (! timeToStop) {
count += 1;
}
}
});
busyThread.start();
Thread.sleep(1000);
timeToStop = true;
busyThread.join();
System.out.println(count);
}
}