一、可见性
1、什么叫做没有可见性
假设两个线程同时去操作主内存中的对象:
比如线程1需要去修改主内存中的data值,线程2只需要去读取主内存中的data值:
new Thread1(){
public void run(){
data++;
}
}.start();
new Thread2(){
public void run(){
while(data==0){
Thread.sleep(100);
}
}
}.start();
当线程1把data的值改成了1后,线程2不一定会立刻就感觉到data的变化;
很有可能在一定的时间范围内,因为之前线程2已经将data=0加载到自己的工作内存中,所以线程2仍处于sleep状态;
这种data已经被线程1更新了,但是线程2在一段时间内仍然看不见的情况就是不具备可见性。
2、什么叫具有可见性
线程1更新完data后,强制线程2重新读取data的值,获得更新后的data。
二、原子性
假设当两个线程同时对主内存中的对象进行操作,如果有原子性,则线程1操作主内存中的data时,线程2不能对主内存中的data进行操作,保证同一时间只有一个线程对主内存中的data进行操作:
三、有序性
以一段代码为例:
flag=false;
//线程1
prepare(); //准备资源
flag=true;
//线程2:如果flag为false则一直等待
while(!flag){
Thread.sleep(1000);
}
execute(); //基于准备好的资源执行操作
对于代码,还有一个问题就是指令重排序,编译器和指令器有时为了提高代码的执行效率,会将指令重排序,比如:
flag=false;
//线程1
flag=true;
prepare(); //准备资源
//线程2:如果flag为false则一直等待
while(!flag){
Thread.sleep(1000);
}
execute(); //基于准备好的资源执行操作
把flag=true;排到了前面,导致线程2不再等待,而线程1的prepare方法还没有执行完,线程2的execute方法在资源没准备完成的情况下执行,导致代码逻辑出现问题。
具备有序性:不会发生指令重排导致代码异常;
不具备有序性:可能发生指令重排导致异常。