定义:如果线程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 {// volatilestatic 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;@Overridepublic 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("主线程进入循环执行~~~~~");}}}
