【Java 并發編程】線程簡介 ( 原子操作 | volatile 關鍵字使用場景 )
文章目錄
一、原子操作
二、volatile 關鍵字使用場景
一、原子操作
原子操作 :
read : 從
主內存
中的線程共享變量中讀取數據 ;
load : 將從主內存讀取到的數據 , 加載到
線程工作內存
中 ;
read 和 load 操作一定是
成對出現
的 , 只要從主內存中讀取到數據 , 一定會將這個數據加載到線程的工作內存中 ;
use : 從線程共享變量副本讀取到線程的
執行引擎
中 ;
assign : 從執行引擎中寫出數據到變量的
共享變量副本
中 ;
store : 將數據從線程工作內存傳輸到
主內存
中 ;
write : 將數據賦值給主內容中的線程
共享變量 ;
lock : 作用于
主內存中的線程共享變量
, 將該變量標識為
被某個線程獨自占用狀態
; 表示該變量只有一個線程可以進行訪問 ;
unlock :
解鎖
主內存中的共享變量 , 其它線程可以進行訪問 ;
二、volatile 關鍵字使用場景
在下面的示例中 , 設置一個標志位 , 主線程開始后 , 啟動一個線程 , 休眠 1000 1000 1000 毫秒 , 然后修改該標志位 , 主線程中根據標志位進行循環 , 如果標志位被修改 , 則循環停止 , 但是循環一直沒有停止 ;
也就是說線程中修改的值 , 僅修改了該線程中工作內存中的標志位副本的值 ;
主內存中的值沒有被修改 ;
代碼示例 :
public class Main { private static boolean flag = false; private static void changeFlag() { System.out.println("修改標志位開始"); flag = true; System.out.println("修改標志位結束"); } public static void main(String[] args) { // 在該線程中 , 1 秒后修改標志位為 false new Thread(){ @Override public void run() { super.run(); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } changeFlag(); } }.start(); // 此處如果 flag 一直為 flase 就會進入死循環 // 如果 flag 為 true 則程序結束 while (!flag) { } System.out.println("主線程結束"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
執行結果 :
原理分析 :
線程的工作內存中 , 將 flag 修改為 true , 這只是在
CPU 緩存
中修改的 ,
沒有在主內存中修改這個共享變量值
, 因此主線程訪問該值 , 還是 false ;
使用 volatile 關鍵字 , 禁用 CPU 的緩存 , 直接在主內存中進行讀寫 , 這樣就可以解決多個線程中 共享變量 不同步的問題 ;
注意 : 只能是 線程共享變量 使用該關鍵字 , 設置該關鍵字會影響線程的執行效率 , 效率會降低 ;
使用了 volatile 關鍵字后的效果 :
public class Main { private static volatile boolean flag = false; private static void changeFlag() { System.out.println("修改標志位開始"); flag = true; System.out.println("修改標志位結束"); } public static void main(String[] args) { // 在該線程中 , 1 秒后修改標志位為 false new Thread(){ @Override public void run() { super.run(); try { sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } changeFlag(); } }.start(); // 此處如果 flag 一直為 flase 就會進入死循環 // 如果 flag 為 true 則程序結束 while (!flag) { } System.out.println("主線程結束"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
執行結果 :
Java 并發的 3 3 3 特性 :
原子性 : 每個操作都是
不可拆分的原子操作
; 在線程中進行 a++ 就不是原子操作 , 該操作分為 3 3 3 個步驟 , 首先從主內存中讀取 a 變量 , 然后進行自增操作 , 最后在將自增后的值寫回主內存中 ;
可見性 :
多個線程
訪問同一個變量 , 該變量一旦被
某個線程修改
, 這些線程必須可以
立刻看到被修改的值 ;
有序性 : 程序按照
代碼先后順序
執行 ;
volatile 關鍵字 , 禁用了 CPU 緩存 , 解決的是共享變量可見性問題 ;
Java 任務調度
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。