连环炮:Java内存模型--》原子性、可见性、有序性--》volatile--》happens-before/内存屏障
并发编程过程中,可能会产生的三类问题:
1.可见性
线程1 run代码:data++
线程2 run代码:while(data == 0){sleep(100);}
没有可见性:
一个线程已经更新了data,另外一个线程看不见
一个线程做data++操作,另外一个线程对data进行读取并判断操作。当线程1执行之前(1)到(6)操作,线程2已经获取到主内存中data的数据。在线程1将值写会主内存之前,他会一直循环等待
有可见性:
当线程1更新完data值时,强制要求线程2要重新从主内存中读取data的值,强制要求其他线程能看到当前的最新值
2.原子性
线程1在执行6道指令的时候,线程2不可以进行操作。可以保证同一时间只有一个线程可以对data进行++操作,保证两个线程同时更新时,不会出现最终data=1的情况
data++,必须是独立执行的,没有其他线程影响,当执行成功之后,其他线程才能进行下一次data++的操作
3.有序性
对于代码,同时还有存在指令重排序的问题。编译器和指令器有的时候为了提高代码执行效率,会将指令重排序
flag = false;
//线程1
prepare();//准备资源
flag = true;
//线程2
while(flag){
Thread.sleep(1000);
}
execute();//基于准备好的资源执行操作
重排序后,让flag=true先执行了,会导致线程2直接跳过while等带,执行某段代码,结果prepare()方法还没有执行,资源还没有准备好,此时会导致代码逻辑出现异常
具备有序性,不会发生指令重排。不具备有序性,可能会发生指令重排,导致代码逻辑异常
指令重排演示
Class T{
int m = 8;
}
T t = new T();
对象创建过程
0 new #2<T> 申请内存,初始化为0
4 invokespecial #3<T. <init>> 变成8
7 astore_1 建立堆栈的联系
8 return (半初始化过程)
4、7互换即为指令重排序
半初始化过程:(1)有堆栈联系 (2)具有初始值