日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 内存模型

發(fā)布時間:2023/12/10 java 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 内存模型 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

為了更好的理解 Java 是如何實現(xiàn) 按需禁用緩存和編譯優(yōu)化 的,我們首先需要對 Java 的內存模型有一個初步的了解。

Java 內存模型主要由以下三部分構成:1 個主內存、n 個線程、n 個工作內存(與線程一一對應),數(shù)據(jù)就在它們三者之間來回倒騰。那么怎么倒騰呢?靠的是 Java 提供給我們的 8 個原子操作:lock、unlock、read、load、use、assign、store、write,其操作流程示意圖如下:


一個變量從主內存拷貝到工作內存,再從工作內存同步回主內存的流程為:

|主內存| -> read -> load -> |工作內存| -> use -> |Java線程| -> assign -> |工作內存| -> store -> write -> |主內存|

Java 內存模型中的 8 個原子操作

  • lock:作用于主內存,把一個變量標識為一個線程獨占狀態(tài)。
  • read:作用于主內存,把一個變量的值從主內存?zhèn)鬏數(shù)骄€程工作內存中,供之后的 load 操作使用。
  • load:作用于工作內存,把 read 操作從主內存中得到的變量值放入工作內存的變量副本中。
  • use:作用于工作內存,把工作內存中的一個變量傳遞給執(zhí)行引擎,虛擬機遇到使用變量值的字節(jié)碼指令時會執(zhí)行。
  • assign:作用于工作內存,把一個從執(zhí)行引擎得到的值賦給工作內存的變量,虛擬機遇到給變量賦值的字節(jié)碼指令時會執(zhí)行。
  • store:作用于工作內存,把工作內存中的一個變量傳送到主內存中,供之后的 write 操作使用。
  • write:作用于主內存,把 store 操作從工作內存中得到的變量值存入主內存的變量中。
  • unlock:作用于主內存,釋放一個處于鎖定狀態(tài)的變量。

8 個原子操作的執(zhí)行規(guī)則

有關變量拷貝過程的規(guī)則

  • 不允許 read 和 load,store 和 write 單獨出現(xiàn)
  • 不允許線程丟棄它最近的 assign 操作,即工作內存變化之后必須把該變化同步回主內存中
  • 不允許一個線程在沒有 assign 的情況下將工作內存同步回主內存中,也就是說,只有虛擬機遇到變量賦值的字節(jié)碼時才會將工作內存同步回主內存
  • 新的變量只能從主內存中誕生,即不能在工作內存中使用未被 load 和 assign 的變量,一個變量在 use 和 store 前一定先經過了 load 和 assign

有關加鎖的規(guī)則

  • 一個變量在同一時刻只允許一個線程對其進行 lock 操作,但是可以被一個線程多次 lock(鎖的可重入)
  • 對一個變量進行 lock 操作會清空這個變量在工作內存中的值,然后在執(zhí)行引擎使用這個變量時,需要通過 assign 或 load 重新對這個變量進行初始化
  • 對一個變量執(zhí)行 unlock 前,必須將該變量同步回主內存中,即執(zhí)行 store 和 write 操作
  • 一個變量沒有被 lock,就不能被 unlock,也不能去 unlock一個被其他線程 lock 的變量

可見性問題 -> 有序性問題

通過上圖可以發(fā)現(xiàn),Java 線程只能操作自己的工作內存,其對變量的所有操作(讀取、賦值等)都必須在工作內存中進行,不能直接讀寫主內存中的變量。這就有可能會導致可見性問題:

  • 因為對于主內存中的變量 A,其在不同的線程的工作內存中可能存在不同的副本 A1、A2、A3。
  • 不同線程的 read 和 load、store 和 write 不一定是連續(xù)執(zhí)行的,中間可以插入其他命令。Java 只能保證 read 和 load、store 和 write 的執(zhí)行對于一個線程而言是連續(xù)的,但是并不保證不同線程的 read 和 load、store 和 write 的執(zhí)行是連續(xù)的,如下圖:

    假設有兩個線程 A 和 B,其中線程 A 在寫入共享變量,線程 B 要讀取共享變量,我們想讓線程 A 先完成寫入,線程 B 再完成讀取。此時即便我們是按照 “線程 A 寫入 -> 線程 B 讀取” 的順序開始執(zhí)行的,真實的執(zhí)行順序也可能是這樣的:storeA -> readB -> writeA -> loadB,這將導致線程 B 讀取的是變量的舊值,而非線程 A 修改過的新值。也就是說,線程 A 修改變量的執(zhí)行先于線程 B 操作了,但這個操作對于線程 B 而言依舊是不可見的。
    那么如何解決這個問題呢?通過上述的分析可以發(fā)現(xiàn),可見性問題的本身,也是由于不同線程之間的執(zhí)行順序得不到保證導致的,因此我們也可以將它的解決和有序性合并,即對 Java 一些指令的操作順序進行限制,這樣既保證了有序性,有解決了可見性。

于是乎,Java 給出了一些命令執(zhí)行的順序規(guī)范,也就是大名鼎鼎 Happens-Before 規(guī)則。

總結

以上是生活随笔為你收集整理的Java 内存模型的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。