public class Thread02 implements Runnable { /**volatile*/ boolean flg = true; @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); while(flg){ //System.out.println("do something"); } System.out.println(Thread.currentThread().getName()+":end"); } public static void main(String[] args) { Thread02 test = new Thread02(); Thread t1 = new Thread(test); t1.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } test.flg=false; } }
上述代码中没有使用volatile关键字,可是在主线程中咱们将flg至为false,可是结果以下:java
public class Thread02 implements Runnable { volatile boolean flg = true; @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); while(flg){ //System.out.println("do something"); } System.out.println(Thread.currentThread().getName()+":end"); } public static void main(String[] args) { Thread02 test = new Thread02(); Thread t1 = new Thread(test); t1.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } test.flg=false; } }
咱们将flg变量前加上volatile关键字,运行结果以下缓存
咱们将睡眠代码注释掉看结果,ide
public class Thread02 implements Runnable { volatile boolean flg = true; @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); while(flg){ //System.out.println("do something"); } System.out.println(Thread.currentThread().getName()+":end"); } public static void main(String[] args) { Thread02 test = new Thread02(); Thread t1 = new Thread(test); t1.start(); // try { // TimeUnit.SECONDS.sleep(1); // } catch (InterruptedException e) { // e.printStackTrace(); // } test.flg=false; } }
你会发现成功了,这是什么缘由呢?spa
分析:线程
这与JVM实现有一些关系,线程读取CPU缓存有关系,在内存和CPU之间还有一层CPU缓存,CPU运行时会将内存中的变量读取并缓存到CPU缓存中,当主线程改变了内存中的变量时,CPU不在读取内存中的变量,而是直接读的自身缓存,产生了主线程与线程数据不一致的状况。加上volatile关键字是告诉CPU每次去内存中读一下,并缓存到本地(并非不读缓存,是每次从内存中COPY),这样达到了一个变量可见的目的。将睡眠时间去掉会成功,说明主线程先于支线程修改了变量,并非每一次都成功的,个人PC是4核的,因此基本每次都是成功的。code
看下面一个问题,很诡异,将while循环中的注释掉的代码打开,去掉volatile关键字,开启睡眠内存
public class Thread02 implements Runnable { /*volatile*/ boolean flg = true; int count = 0; @Override public void run() { System.out.println(Thread.currentThread().getName()+":start"); while(flg){ count++; System.out.println(count+":do something"); } System.out.println(Thread.currentThread().getName()+":end"); } public static void main(String[] args) { Thread02 test = new Thread02(); Thread t1 = new Thread(test); t1.start(); try { TimeUnit.SECONDS.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } test.flg=false; } }
看结果:get
正常结束了,不是内存中变量不可见了么,怎么还正常结束呢?it
分析:io
确定是CPU去读过内存了,具体什么时间不知道,这和CPU的工做机制有关,当CPU空闲的时候会读取内存数据缓存到本地,注意观察count值,咱们再运行一遍
两次结果不一致,确切的说每次结果不一致,可是大概范围不会差距很大