【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )
文章目錄
- 一、原子操作
- 二、volatile 關(guān)鍵字使用場景
一、原子操作
原子操作 :
read : 從 主內(nèi)存 中的線程共享變量中讀取數(shù)據(jù) ;
load : 將從主內(nèi)存讀取到的數(shù)據(jù) , 加載到 線程工作內(nèi)存 中 ;
read 和 load 操作一定是 成對出現(xiàn) 的 , 只要從主內(nèi)存中讀取到數(shù)據(jù) , 一定會(huì)將這個(gè)數(shù)據(jù)加載到線程的工作內(nèi)存中 ;
use : 從線程共享變量副本讀取到線程的 執(zhí)行引擎 中 ;
assign : 從執(zhí)行引擎中寫出數(shù)據(jù)到變量的 共享變量副本 中 ;
store : 將數(shù)據(jù)從線程工作內(nèi)存?zhèn)鬏數(shù)?主內(nèi)存 中 ;
write : 將數(shù)據(jù)賦值給主內(nèi)容中的線程 共享變量 ;
lock : 作用于 主內(nèi)存中的線程共享變量 , 將該變量標(biāo)識(shí)為 被某個(gè)線程獨(dú)自占用狀態(tài) ; 表示該變量只有一個(gè)線程可以進(jìn)行訪問 ;
unlock : 解鎖 主內(nèi)存中的共享變量 , 其它線程可以進(jìn)行訪問 ;
二、volatile 關(guān)鍵字使用場景
在下面的示例中 , 設(shè)置一個(gè)標(biāo)志位 , 主線程開始后 , 啟動(dòng)一個(gè)線程 , 休眠 100010001000 毫秒 , 然后修改該標(biāo)志位 , 主線程中根據(jù)標(biāo)志位進(jìn)行循環(huán) , 如果標(biāo)志位被修改 , 則循環(huán)停止 , 但是循環(huán)一直沒有停止 ;
也就是說線程中修改的值 , 僅修改了該線程中工作內(nèi)存中的標(biāo)志位副本的值 ;
主內(nèi)存中的值沒有被修改 ;
代碼示例 :
public class Main {private static boolean flag = false;private static void changeFlag() {System.out.println("修改標(biāo)志位開始");flag = true;System.out.println("修改標(biāo)志位結(jié)束");}public static void main(String[] args) {// 在該線程中 , 1 秒后修改標(biāo)志位為 falsenew Thread(){@Overridepublic void run() {super.run();try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}changeFlag();}}.start();// 此處如果 flag 一直為 flase 就會(huì)進(jìn)入死循環(huán)// 如果 flag 為 true 則程序結(jié)束while (!flag) {}System.out.println("主線程結(jié)束");} }執(zhí)行結(jié)果 :
原理分析 :
線程的工作內(nèi)存中 , 將 flag 修改為 true , 這只是在 CPU 緩存 中修改的 , 沒有在主內(nèi)存中修改這個(gè)共享變量值 , 因此主線程訪問該值 , 還是 false ;
使用 volatile 關(guān)鍵字 , 禁用 CPU 的緩存 , 直接在主內(nèi)存中進(jìn)行讀寫 , 這樣就可以解決多個(gè)線程中 共享變量 不同步的問題 ;
注意 : 只能是 線程共享變量 使用該關(guān)鍵字 , 設(shè)置該關(guān)鍵字會(huì)影響線程的執(zhí)行效率 , 效率會(huì)降低 ;
使用了 volatile 關(guān)鍵字后的效果 :
public class Main {private static volatile boolean flag = false;private static void changeFlag() {System.out.println("修改標(biāo)志位開始");flag = true;System.out.println("修改標(biāo)志位結(jié)束");}public static void main(String[] args) {// 在該線程中 , 1 秒后修改標(biāo)志位為 falsenew Thread(){@Overridepublic void run() {super.run();try {sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}changeFlag();}}.start();// 此處如果 flag 一直為 flase 就會(huì)進(jìn)入死循環(huán)// 如果 flag 為 true 則程序結(jié)束while (!flag) {}System.out.println("主線程結(jié)束");} }執(zhí)行結(jié)果 :
Java 并發(fā)的 333 特性 :
- 原子性 : 每個(gè)操作都是 不可拆分的原子操作 ; 在線程中進(jìn)行 a++ 就不是原子操作 , 該操作分為 333 個(gè)步驟 , 首先從主內(nèi)存中讀取 a 變量 , 然后進(jìn)行自增操作 , 最后在將自增后的值寫回主內(nèi)存中 ;
- 可見性 : 多個(gè)線程 訪問同一個(gè)變量 , 該變量一旦被 某個(gè)線程修改 , 這些線程必須可以 立刻看到被修改的值 ;
- 有序性 : 程序按照 代碼先后順序 執(zhí)行 ;
volatile 關(guān)鍵字 , 禁用了 CPU 緩存 , 解決的是共享變量可見性問題 ;
總結(jié)
以上是生活随笔為你收集整理的【Java 并发编程】线程简介 ( 原子操作 | volatile 关键字使用场景 )的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 并发编程】线程简介 ( 并发
- 下一篇: 【Java 并发编程】线程指令重排序问题