JMM內存模型-多線程讀寫測試

概述

JMM層面理解多線程對共享變量修改時的可見性問題。
在這裏插入圖片描述

源碼

/**
 * <pre>
 * 測試兩個線程,對同一個局部變量進行修改,是否可見
 * 1、啓動[1號線程],啓動後,等待flag值變爲true,則繼續執行、然後退出循環
 * 2、啓動[2號線程],啓動後,該線程會把flag值改成true
 * 3、觀察輸出,看[2號線程]修改flag後,[1號線程]是否可以感知到。
 * 如果[1號線程]繼續執行了,則表明讀到了修改後的值;如果沒有執行,說明沒有讀到修改後的值。
 * 關鍵字:volatile
 * </pre>
 * created at 2020-05-30 08:26
 * @author lerry
 */
public class VolatileDemo {

	private static boolean flag = false;

	public static void main(String[] args) throws InterruptedException {
		Thread thread1 = new Thread(() -> {
			System.out.printf("[1號線程]啓動\n");
			while (true) {
				if (flag) {
					System.out.printf("[1號線程]執行標記修改後的代碼\n");
					break;
				}
			}
			System.out.printf("[1號線程]結束\n");
		});
		thread1.start();

		int seconds = 1;
		Thread.sleep(seconds * 1000);

		new Thread(() -> {
			System.out.printf("[2號線程]當前標記爲:[%s]\n", flag);
			flag = true;
			System.out.printf("[2號線程]修改後標記爲:[%s]\n", flag);

		}).start();
	}
}

執行結果

[1號線程]啓動
[2號線程]當前標記爲:[false]
[2號線程]修改後標記爲:[true]

結論

[2號線程]修改`flag`值後,[1號線程]並不知道

加上volatile關鍵字

private static volatile boolean flag = false;

加了volatile後的執行結果

[1號線程]啓動
[2號線程]當前標記爲:[false]
[2號線程]修改後標記爲:[true]
[1號線程]執行標記修改後的代碼
[1號線程]結束

結論

爲何不加volatile關鍵字時,[1號線程]讀取不到[2號線程]對共享變量flag的修改呢?
靜態變量,剛開始是在主內存中。當兩個線程都使用到flag時,jvm會把這個變量複製到各自的工作內存中存一份副本。
[2號線程]只是把自己工作內存種的副本給修改了,這時[1號線程]當然不知道flag值已經修改了。

volatile 強制變量的賦值會同步刷新回主內存,強制變量的讀取會從主內存重新加載,保證不同的線程總是能夠看到該變量的最新值。

加了volatile之後,[2號線程]修改了flag值之後,會刷新回主內存,[1]號線程讀取時,從主內存重新加載,這時[1號線程]就讀取到修改後的flag值了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章