从头认识多线程-3.1 使用volatile解决异步死循环

来源:互联网 发布:轩辕剑6 知乎 编辑:程序博客网 时间:2024/06/03 19:51

这一章节我们来讨论一下使用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--------");}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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;}@Overridepublic 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



0 0
原创粉丝点击