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,但是结果如下:
  
   
  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关键字,运行结果如下
  
  我们将睡眠代码注释掉看结果,
  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; 	} }
  
  你会发现成功了,这是什么原因呢?
  分析:
  这与JVM实现有一些关系,线程读取CPU缓存有关系,在内存和CPU之间还有一层CPU缓存,CPU运行时会将内存中的变量读取并缓存到CPU缓存中,当主线程改变了内存中的变量时,CPU不在读取内存中的变量,而是直接读的自身缓存,产生了主线程与线程数据不一致的情况。加上volatile关键字是告诉CPU每次去内存中读一下,并缓存到本地(并不是不读缓存,是每次从内存中COPY),这样达到了一个变量可见的目的。将睡眠时间去掉会成功,说明主线程先于支线程修改了变量,并不是每一次都成功的,我的PC是4核的,所以基本每次都是成功的。
  看下面一个问题,很诡异,将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; 	} }
  看结果:
  
  正常结束了,不是内存中变量不可见了么,怎么还正常结束呢?
  分析:
  肯定是CPU去读过内存了,具体什么时间不知道,这和CPU的工作机制有关,当CPU空闲的时候会读取内存数据缓存到本地,注意观察count值,我们再运行一遍
  
  两次结果不一致,确切的说每次结果不一致,但是大概范围不会差距很大