定义:如果线程A中的一个操作对线程B是可见的,那么这个操作的执行成功后结果将立刻被线程B发现。
多核时代,每颗 CPU 都有自己的缓存,当多个线程在不同的 CPU 上执行时,这些线程操作的是不同的 CPU 缓存。线程 A 操作的是 CPU-1 上的缓存,而线程 B 操作的是 CPU-2 上的缓存,很明显,这个时候线程 A 对变量 V 的操作对于线程 B 而言就不具备可见性了。
在多线程的环境下,如果某个线程首次读取共享变量,则首先到主内存中获取该变量,然后存入工作内存中,以后只需要在工作内存中读取该变量即可。同样如果对该变量执行了修改的操作,则先将新值写入工作内存中,然后再刷新至主内存中。但是什么时候最新的值会被刷新至主内存中是不太确定,一般来说会很快,但具体时间不知。
要解决共享对象可见性这个问题,我们可以使用volatile关键字或者是加锁。
一个常见的可见性的例子
实际上这个例子不是可见性的问题,因为在while里面加入一句输出hello,(System.out.println()里面有synchornized),线程会停止运行。
参见 hllvm-group.iteye.com/group/topic/34932
public class Test {
// volatile
static boolean flag = true;
public static void main(String[] args) throws InterruptedException {
new Thread(()->{
while(flag){
}
}).start();
TimeUnit.SECONDS.sleep(1);
new Thread(()->{
flag=false;
}).start();
}
}
而是编译优化指令重排引起的问题,
一个关于可见性的问题
直接运行,进不去if。
放开这段代码中的注释,就能进入到if中。
不使用for循环直接new Object(); 也进不去。
原因未知。
public class Test2 {
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
while(true){
// for (int i = 0; i < 2; i++) {
// new Object();
// }
if(t.getFlag()){
System.out.println("主线程进入循环执行~~~~~");
}
}
}
}
class MyThread extends Thread{
private boolean flag = false;
@Override
public void run() {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
flag = true;
System.out.println("flag="+flag);
}
public boolean getFlag() throws InterruptedException {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}
将new Object(); 换成 int ,进不去
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
while(true){
for (int i = 0; i < 2; i++) {
int ss = 1;
}
if(t.getFlag()){
System.out.println("主线程进入循环执行~~~~~");
}
}
}
再将for循环的次数改成1 ,能进去
public static void main(String[] args) throws InterruptedException {
MyThread t = new MyThread();
t.start();
while(true){
for (int i = 0; i < 1; i++) {
int ss = 1;
}
if(t.getFlag()){
System.out.println("主线程进入循环执行~~~~~");
}
}
}