本人在编写下面代码是遇到了线程关闭不了的问题,最后通过加volatile解决了相关问题,对内部原因在查阅资料后明白类一些
代码如下:
package com.mec.thread_pool.test;
public class TaskRunByThread implements Runnable {
private static int id;
private boolean goon;
private int currentId;
public TaskRunByThread() {
goon = true;
currentId = ++id;
new Thread(this, "Thread-" + currentId).start();
}
public void stopThread() {
System.out.println("收到结束线程[" + Thread.currentThread().getName()
+ "]的命令!");
goon = false;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + "线程开始!");
while (goon) {
}
System.out.println(Thread.currentThread().getName() + "线程结束!");
}
}
package com.mec.thread_pool.test;
public class Test {
public static void main(String[] args) {
TaskRunByThread byThread = new TaskRunByThread();
try {
Thread.sleep(1000);
byThread.stopThread();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
通过main()出来的主线程来创造和关闭一个新线程;但是如果goon不加volatiled输出如下:
Thread-1收到main的结束命令,但是Thread-1并没有结束(通过右上角的小红点和输出可以看出来);
这是由于现在CPU的运算速度快速提高,但计算机的IO操作却跟不上计算机的运算速度,所以出现了寄存器以及缓存区,对于计算机某个进程需要多次用到的数据,他会拷贝一份副本放在缓存区里;结构图如下:
越靠近CPU重里面读取数据的速度也就越快,空间也越小;
Thread-1线程在执行时候由于while里面非常简单所以,他会把goon复制一份到缓存区。判断循环是否继续条件的时候他会直接从缓存区中得到goon。而main线程却改变的是RAM中Thread-1数据区的goon。而Thread-1不会区查看RAM中的数据一直执行下去,造成Thread-1关闭不了。
在加上volatile之后,main线程在更改goon的值后,当Thread-1线程使用缓存区中的他自己的goon时,他会发现该变量被标记为失效,他会去和RAM中的goon同步,这样就不会不会出现Thread-1结束不了的情况了。
加上volatile后执行结果如下: