在Java中,volatile 是一个关键字,用于修饰类的实例变量。volatile 的主要作用是保证多个线程能够正确地处理被多个线程共享的变量。当一个变量被声明为volatile时,它具有以下两个特性:
尽管volatile提供了一定程度的线程安全,但它并不能完全替代锁。volatile适用于那些变量的写操作不依赖于当前值的情况,例如标志位的修改。但对于一些复合操作,仍然需要使用锁来确保原子性。
需要注意的是,volatile并不能保证原子性,因此不能替代synchronized关键字。如果需要确保一系列操作的原子性,还是需要使用锁。
public class NonVolatileExample {
private boolean flag = false;
public static void main(String[] args) {
NonVolatileExample example = new NonVolatileExample();
// 线程1:修改flag的值
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(1000); // 模拟一些耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
example.setFlag(true);
System.out.println("Flag is set to true by Thread 1");
});
// 线程2:检查flag的值
Thread thread2 = new Thread(() -> {
while (!example.isFlag()) {
// 等待flag变为true
}
System.out.println("Flag is true, Thread 2 can proceed");
});
thread1.start();
thread2.start();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
当运行上述示例,会在while (!example.isFlag())
处一直卡着,说明线程thread2读取flag一直读取的是旧值
public class NonVolatileExample {
private boolean flag = false;
public static void main(String[] args) {
NonVolatileExample example = new NonVolatileExample();
// 线程1:修改flag的值
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(1000); // 模拟一些耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
example.setFlag(true);
System.out.println("Flag is set to true by Thread 1");
});
// 线程2:检查flag的值
Thread thread2 = new Thread(() -> {
while (!example.isFlag()) {
// 等待flag变为true
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Flag is true, Thread 2 can proceed");
});
thread1.start();
thread2.start();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
当在线程thread2中加上Thread.sleep(1000)
就没有出现while中长时间等待的情况,这里说明thread2线程还是可以读取到thread1修改后的数据,只是什么时候放弃缓存读取主存的时机不由java程序控制,是由操作系统及计算机硬件决定,所以会导致示例一的情况,thread1修改过很长时间后thread2才能读取到共享对象
public class NonVolatileExample {
private volatile boolean flag = false;
public static void main(String[] args) {
NonVolatileExample example = new NonVolatileExample();
// 线程1:修改flag的值
Thread thread1 = new Thread(() -> {
try {
Thread.sleep(1000); // 模拟一些耗时操作
} catch (InterruptedException e) {
e.printStackTrace();
}
example.setFlag(true);
System.out.println("Flag is set to true by Thread 1");
});
// 线程2:检查flag的值
Thread thread2 = new Thread(() -> {
while (!example.isFlag()) {
// 等待flag变为true
}
System.out.println("Flag is true, Thread 2 can proceed");
});
thread1.start();
thread2.start();
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
加上volatile关键字后java就能控制读取主存的时机