1. 程式人生 > >java多執行緒4:關鍵字volatile

java多執行緒4:關鍵字volatile

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了