从头认识多线程-3.1 使用volatile解决异步死循环
Posted 李灵晖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了从头认识多线程-3.1 使用volatile解决异步死循环相关的知识,希望对你有一定的参考价值。
这一章节我们来讨论一下使用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是-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
以上是关于从头认识多线程-3.1 使用volatile解决异步死循环的主要内容,如果未能解决你的问题,请参考以下文章
多线程---再次认识volatile,Synchronize,lock
从头认识多线程-1.8 迫使线程停止的方法-暴力Stop方法