什么是volatile关键字
volatile关键字的作用:保证了变量的可见性(visibility)。被volatile关键字修饰的变量,如果值发生了变更,其他线程立马可见,避免出现脏读的现象。
例如以下程序:
public class Test {
public static void main(String[] args) {
DemoThread thread = new DemoThread();
new Thread(thread).start();
while (true) {
if (thread.isFlag()) {
System.out.println("---------------");
break;
}
}
}
}
class DemoThread implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setFlag(true);
System.out.println("flag is " + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
} 这段程序,会不会打印出横线呢?显然是不会的,为什么呢?这个时候就涉及到了内存可见性。
内存可见性
实际上,当我们的程序运行时,JVM会为每一个执行任务的线程分配一个独立的缓存以提高其运行效率。所以当两个及以上的线程操作共享数据时,彼此不可见。原理如下:
解决
使用synchronized关键字。
public class Test {
public static void main(String[] args) {
DemoThread thread = new DemoThread();
new Thread(thread).start();
while (true) {
synchronized (thread) {
if (thread.isFlag()) {
System.out.println("---------------");
break;
}
}
}
}
}
class DemoThread implements Runnable {
private boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setFlag(true);
System.out.println("flag is " + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
} 但是synchronized关键字效率低,当第一个线程获取到锁之后,之后的线程会对锁进行检测,如果锁被占用,则会被阻塞,然后等待后续的cpu调度执行。有没有更好的方法呢?
volatile
volatile关键字的作用是当多个线程进行操作共享数据时,可以保证内存中的数据可见。我们也可以将其理解为多个线程操作被volatile关键字修饰的数据时相当于直接操作的主存中的数据。这样对各个变量来说,这些被修饰的数据都是实时可见的。但是volatile关键字的效率也低,被volatile关键字修饰的变量不能进行JVM底层的优化(重排序),但是其效率是比synchronized关键字高的。volatile相较于synchronized是一种较为轻量级的同步策略。
public class TestVolatile {
public static void main(String[] args) {
DemoThread thread = new DemoThread();
new Thread(thread).start();
while (true) {
if (thread.isFlag()) {
System.out.println("---------------");
break;
}
}
}
}
class DemoThread implements Runnable {
private volatile boolean flag = false;
@Override
public void run() {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setFlag(true);
System.out.println("flag is " + isFlag());
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
} 注意
1.volatile关键字不具备互斥性。synchronized具备互斥性。
2.volatile关键字仅仅能保证变量写操作的原子性,不保证复合操作,比如说读写操作的原子性

京公网安备 11010502036488号