概念
volatile称之为轻量级锁,被volatile修饰的变量,在线程之间是可见的(一个线程修改了这个变量的值,在另外一个线程中能够读到这个修改后的值。)
作用
volatile保证可见性的前提:多个线程获取的是同一把锁
使用
线程一执行完毕后,线程二才能执行
public class Demo2 {
public volatile boolean run = false;
public static void main(String[] args) {
Demo2 d = new Demo2();
new Thread(new Runnable() {
@Override
public void run() {
for(int i = 1;i<=10;i++) {
System.err.println("执行了第 " + i + " 次");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
d.run = true;
}
}).start();
new Thread(new Runnable() {
@Override
public void run() {
//判断上一个线程是否将run置为了true
while(!d.run) {
// 不执行
}
System.err.println("线程2执行了...");
}
}).start();
}
}
volatile底层实现
a. lock指令生效
i. 在多处理器的系统上:
1) 将当前处理器缓存行(cpu缓存的最小单位)写回到系统内存
2) 这个写回到内存的操作会使再其他cpu缓存了该内存的地址的数据失效,保证数据一致性
b. 如果不加volatile,当前处理器的缓存行不会立刻写回到内存,这样其他线程就是旧数据
缺陷
使用适当可以提升性能;如果大量使用volatile,cpu内存就会失效,降低性能
比较
a. volatile,轻量级锁,可以保证可见性,但是不能保证操作的原子性;volatile替代不来synchronized
b. synchronized,重量级锁,也可以保证可见性,也能保证操作的原子性,synchronized可以替代volatile
c. volatile存在的意义就是,如果只是原子性操作,使用volatile比synchronized更轻量化
/**
*
如果get方法中只是“return a”,那么就可
以用volatile替换synchronized,更加轻量化。但是
如果get方法中是“return a++”,这是一个非原子性操作(包括加和赋值两个操作),就只能使用synchronized来保证线程安全
*/
public class Demo {
int a = 1;
public synchronized int getA() {
return a++;
}
public synchronized void setA(int a) {
try {
Thread.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.a = a;
}
}