java多執行緒4:關鍵字volatile
阿新 • • 發佈:2018-12-20
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了