上一篇我们说了在保证数据一致性方面需要满足三个特性原子性 可见性 有序性
。
在java当中volatile
这个关键字有如下特性
- 保证可见性
- 不保证原子性
- 禁止指令重排
可见性
public class VolatileApp{
private static boolean initFlag = false;
public static void main( String[] args ) {
//线程A
new Thread(new Runnable() {
@Override
public void run() {
while (!initFlag){
}
System.out.printf("initFlag-----"+initFlag);
}
}).start();
//线程B
new Thread(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("aaaaaaa");
initFlag = true;
System.out.println("aaaaaaa");
}
}).start();
}
}
运行结果显而易见,线程B中
initFlag
修改值为true
后,线程A并没有接收到这个信息,要让A能够立即指导initFlag
修改后的值,加入volatile
关键字并能解决这个问题,这就是一个很典型的内存可见性问题的场景。
//修改代码如下
private volatile static boolean initFlag = false;
不保证原子性
首先我们来看下面这一句代码
public volatile int incre = 0;
public void increase() {
incre ++;
}
我们开启线程运行increase()
方法,假如10个线程,循环运行100次,理想状态下,得到的结果incre
打印出来的结果会是1000,可是实际运行出来的情况肯定不是这样的,一般都会小于1000这个数。
我们说了volatile
保证变量在主内存的可见性,在值修改后会通知其他线程去获取最新的值,可是在这个地方incre++
这个操作并不是一个原子性操作,这里解释一下,自增操作是不具备原子性的,它包括读取变量的原始值、进行加1操作、写入工作内存。