这一章节我们来讨论一下使用volatile解决异步死循环。
1.在讨论上面的问题前,我们引入另一个例子:同步死循环
代码清单:
package com.ray.deepintothread.ch03.topic_1; public class DeadFor { private boolean isStop = false; public boolean isStop() { return isStop; } public void setStop(boolean isStop) { this.isStop = isStop; } public void test() throws InterruptedException { while (!isStop) { System.out.println("Thread name:" + Thread.currentThread().getName()); Thread.sleep(200); } } public static void main(String[] args) throws InterruptedException { DeadFor deadFor = new DeadFor(); deadFor.test(); deadFor.setStop(true); } }
输出:
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
Thread name:main
。。。。
上面的例子里面,test方法已经阻塞了main后面所有方法的执行。
2.解决同步死循环的方法:使用异步
package com.ray.deepintothread.ch03.topic_1; public class SolveDeadFor implements Runnable { private boolean isStop = false; public boolean isStop() { return isStop; } public void setStop(boolean isStop) { this.isStop = isStop; } public void test() throws InterruptedException { while (!isStop) { System.out.println("Thread name:" + Thread.currentThread().getName()); Thread.sleep(200); } } public static void main(String[] args) throws InterruptedException { SolveDeadFor deadFor = new SolveDeadFor(); Thread thread = new Thread(deadFor); thread.start(); Thread.sleep(1000); deadFor.setStop(true); System.out.println("-------stop--------"); } @Override public void run() { try { test(); } catch (InterruptedException e) { e.printStackTrace(); } } }
输出:
Thread name:Thread-0
Thread name:Thread-0
Thread name:Thread-0
Thread name:Thread-0
Thread name:Thread-0
-------stop--------
上面的方法我们需要注意的是:test方法我们是单独启动一个线程来运行的,不再是放在main里面运行
因此,test方法与main里面执行的方法是并行的两条线,永远不会发生交集,就会避免了上面的同步的时候,test方法执行后,阻塞下面所有方法的执行
当在等待时间过后,我们触发一下对象里面的状态域,使得test方法停下来
3.异步死循环
代码清单:
package com.ray.deepintothread.ch03.topic_1; public class SolveDeadFor { public static void main(String[] args) throws InterruptedException { MyClassOne myClassOne = new MyClassOne(); myClassOne.start(); Thread.sleep(1000); myClassOne.setStop(true); System.out.println("---------stop----------"); } } class MyClassOne extends Thread { private boolean isStop = false; public boolean isStop() { return isStop; } public void setStop(boolean isStop) { this.isStop = isStop; } @Override public void run() { System.out.println("running"); while (!isStop) { } System.out.println("out"); } }
上面的代码注意:在这里run里面的循环必须是空循环才能够出现死循环
笔者估计,isStop经过编译器的编译,读取的是局部变量,因此,即便是外部修改了域,里面读取的地方不是我们想要的地方
jvm设置:
注意:这里必须要jvm是-server状态下才能够出现异步死循环。
输出:
running
---------stop----------
(不会出现out)
我们通过jvm的内存模型来解释上面的现象
注:图片摘自java多线程编程核心技术
由上面的内存模型可以看见,当我们线程起来之后,我们修改了线程私有的工作内存,还会把某些值写入到主内存里面去
然后,当我们修改这些工作内存的时候,一般会同步到主内存去
但是,我们上面的代码只是修改了工作内存,而没有同步到主内存,因此,当我们外部修改工作内存的时候,run里面读取的isStop是主内存里面的,没有被修改,会出现异步死循环。
我们下面展示一下不会出现异步死循环的代码,只需要在循环里面加一两句代码即可
package com.ray.deepintothread.ch03.topic_1; public class DeadForSynch2 { public static void main(String[] args) throws InterruptedException { MyClassTwo myClassOne = new MyClassTwo(); myClassOne.start(); Thread.sleep(1000); myClassOne.setStop(true); System.out.println("---------stop----------"); } } class MyClassTwo extends Thread { private boolean isStop = false; public boolean isStop() { return isStop; } public void setStop(boolean isStop) { this.isStop = isStop; } @Override public void run() { System.out.println("running"); while (!isStop) { System.out.println(Thread.currentThread().getName()); try { sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println("out"); } }
输出:
running
Thread-0
Thread-0
Thread-0
---------stop----------
out
4.异步死循环的解决方案
代码清单:
package com.ray.deepintothread.ch03.topic_1; public class SolutionOfDeadForAsychn { public static void main(String[] args) throws InterruptedException { MyClassThree myClassThree = new MyClassThree(); myClassThree.start(); Thread.sleep(1000); myClassThree.setStop(true); System.out.println("---------stop----------"); } } class MyClassThree extends Thread { private volatile boolean isStop = false; public boolean isStop() { return isStop; } public void setStop(boolean isStop) { this.isStop = isStop; } @Override public void run() { System.out.println("running"); while (!isStop) { } System.out.println("out"); } }
输出:
running
out
---------stop----------
我们上面使用volatile来把isStop强制同步到主内存去,使得其他线程能够可见。
总结:这一章节讨论了使用volatile解决异步死循环。
这一章节就到这里,谢谢
------------------------------------------------------------------------------------
我的github:https://github.com/raylee2015/DeepIntoThread
目录:http://blog.csdn.net/raylee2007/article/details/51204573