从头认识多线程-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是-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
- 从头认识多线程-3.1 使用volatile解决异步死循环
- 从头认识多线程-3.3 synchronized某些解决不了的可视性问题,只能使用volatile来解决
- 利用volatile解决异步死循环的问题
- 从头认识多线程-3.2 使用volatile声明的变量的写操作是非原子性的
- 从头认识C—volatile
- 从头认识多线程-目录
- 从头认识多线程-目录
- 从头认识java-17.1 多线程
- 从头认识多线程-1.3 currentThread()
- 从头认识多线程-1.14 优先级
- 从头认识多线程-2.10 同步代码块的特殊现象:一半同步,一半异步
- 从头认识多线程-2.14 由同步的synchronized (newobject()) 引起的异步现象和脏读
- 从头认识多线程-1.1 多线程的创建
- 从头认识多线程-2.16 证明使用整数属性域作为多线程监视器是不同步的
- 从头认识多线程-2.15 解决由同步的synchronized (newobject()) 引起的脏读的方法
- HashMap多线程死循环问题
- HashMap多线程死循环问题
- HashMap多线程死循环问题
- 使用virtualenv或virtualenvwrapper搭建独立的python开发环境
- 解决IdTCPClient和IdTCPServer通信中文乱码问题
- java -version 错误
- php学习第三天----pdo操作
- ASP.NET将数据导出到一个EXCEL文件的多个SHEET中
- 从头认识多线程-3.1 使用volatile解决异步死循环
- C++第六次作业
- c++第7次实验:最大公约数和最小公倍数
- LeetCode--No.142--Linked List Cycle II
- eog——Eye of GNOME Image Viewer
- c++第四次作业
- c++实验7-数组素数排序
- HDU:2099 整除的尾数(水)
- UINavigationItem返回按钮自定义设置