java多线程4:关键字volatile
a.volatile关键字的作用:
使用volatile关键字增加了实例变量在多个线程之间的可见性。
如果没有使用这个关键字,出现如下现象:
这个时候就是私有堆栈和公共堆栈的值不同步。如果改变了公共堆栈中的值后,私有的依旧没有变化。如果添加了volatile关键字,这个变量就是和共有部分同步了。
b.案例解释:
package multiThread.volatilePack;
public class MyThread extends Thread {
boolean b = true;
public boolean isRunning() {
return b;
}
public void setRunning(boolean b) {
this.b = b;
}
public void run() {
System.out.println("进入了running了");
System.out.println(b + " 这个是进入循环前的b----------");
while (b == true) {
// System.out.println("进入循环");
}
System.out.println("线程被停止了");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
myThread.setRunning(false);
System.out.println("已经设置为false了");
}
}
控制台:
如果我们对变量b前边添加一个关键字volatile:
package multiThread.volatilePack;
public class MyThread extends Thread {
volatile boolean b = true;
public boolean isRunning() {
return b;
}
public void setRunning(boolean b) {
this.b = b;
}
public void run() {
System.out.println("进入了running了");
System.out.println(b + " 这个是进入循环前的b----------");
while (b == true) {
// System.out.println("进入循环");
}
System.out.println("线程被停止了");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
myThread.setRunning(false);
System.out.println("已经设置为false了");
}
}
控制台:
b.再看几个现象,关于jvm的两种运行模式
client和server,64位只有server模式,client是无效的。参考下边链接,我们上边的就是在64位server下测试的。如果是32的client就不一样了。
https://blog.csdn.net/Erica_1230/article/details/69934787
c.在while循环中,加入了打印语句的时候,上边的测试代码第一个情况就会不一样,有了打印语句后,我们当前线程也会跳转到公共值栈中取值,所以也会和公共值栈同步,所以会导致程序while中的b变为main中赋值的false
参考链接:https://blog.csdn.net/Ditto_zhou/article/details/83751386
下边的测试代码对第一个进行修改后:
package multiThread.volatilePack;
public class MyThread extends Thread {
boolean b = true;
public boolean isRunning() {
return b;
}
public void setRunning(boolean b) {
this.b = b;
}
public void run() {
System.out.println("进入了running了");
System.out.println(b + " 这个是进入循环前的b----------");
while (b == true) {
System.out.print("进入循环");
}
System.out.println("线程被停止了");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
try {
Thread.sleep(10);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
myThread.setRunning(false);
System.out.println("已经设置为false了");
}
}
控制台:
d.在main函数中是否添加sleep可能会导致效果不一样,有可能会改变进入while循环前b的值。因为最开始默认的b是true,但是在main线程中,修改为了false,但是进入while循环的时候,b到底是true还是false呢?这个就看执行时间 了
下边测试代码就是去掉主函数中的sleep函数,这个时候,我们main函数中的myThread.setRunning(false);就在while前先把b的值给改变了
package multiThread.volatilePack;
public class MyThread extends Thread {
boolean b = true;
public boolean isRunning() {
return b;
}
public void setRunning(boolean b) {
this.b = b;
}
public void run() {
System.out.println("进入了running了");
System.out.println(b + " 这个是进入循环前的b----------");
while (b == true) {
System.out.print("进入循环");
}
System.out.println("线程被停止了");
}
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
// try {
// Thread.sleep(10);
// } catch (InterruptedException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
myThread.setRunning(false);
System.out.println("已经设置为false了");
}
}
控制台:
这里看到进入while的时候,b已经被修改为了false了