volatile基本介绍
volatile可以看成是synchronized的一种轻量级的实现,但volatile并不能完全代替synchronized,volatile有synchronized可见性的特性,但没有synchronized原子性的特性。可见性即用volatile关键字修饰的成员变量表明该变量不存在工作线程的副本,线程每次直接都从主内存中读取,每次读取的都是最新的值,这也就保证了变量对其他线程的可见性。另外,使用volatile还能确保变量不能被重排序,保证了有序性。
volatile只用修饰一个成员变量,如:private volatile balance;
volatile比synchronized编程更容易且开销更小,但具有一点的使用局限性,使用要相当小心,不能当锁使用。volatile不会像synchronized一样阻塞程序,如果是读操作远多于写操作的情况可以建议使用volatile,它会有更好的性能。
volatile使用场景
如果正确使用volatile的话,必须依赖下以下种条件:
1、对变量的写操作不依赖当前变量的值;
2、该变量没有包含在其他变量的不变式中。
第1个条件就说明了volatile不是原子性的操作,不能使用n++类似的计数器,它不是线程安全的。
test1:
private static volatile int n1 = 0;
public static void main(String[] args){
new Thread1().start();
while (n1 == 0) {
}
System.out.println("stop");
}
static class Thread1 extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
n1=1;
}
}
test1这个程序加了volatile,所以程序可以正常退出,输出stop
test2:
private static int n2 = 0;
public static void main(String[] args){
new Thread1().start();
while (n2 == 0) {
System.out.println(n2);
}
System.out.println("stop");
}
static class Thread1 extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
n2=1;
}
}
test2这个例子没有加volatile,程序也正常退出并输出一堆0并输出了stop,这是为什么呢?没有加volatile为什么也有可见性?看起来是很诡异的问题,问题是在while里面加了一行System…输出问题,打开源码看println方法里面加了synchronized同步块,正是因为这个同步块保证了里面变量x的可见性,这个诡异的问题也就解开了。
/**
* Prints an integer and then terminate the line. This method behaves as
* though it invokes <code>{@link #print(int)}</code> and then
* <code>{@link #println()}</code>.
*
* @param x The <code>int</code> to be printed.
*/
public void println(int x) {
synchronized (this) {
print(x);
newLine();
}
}
test3:
private static int n3 = 0;
public static void main(String[] args){
new Thread1().start();
while (n3 == 0) {
}
System.out.println("stop");
}
static class Thread1 extends Thread {
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
n3=1;
}
}
test3这个例子即没加volatile,也没有在while里面加System…输出语句,所以线程对变量n3的修改对主线程不可见,程序一直循环,没有输出结果。