2019年Java大廠面試題講解(周陽) 之Volatile和JMM內存模型的可見性

      網友投稿 837 2022-05-30

      Volatile和JMM內存模型的可見性

      談談對Volatile的理解

      JMM是什么

      JMM的特性

      可見性代碼驗證

      JUC(java.util.concurrent)

      進程和線程

      進程:后臺運行的程序(我們打開的一個軟件,就是進程)

      線程:輕量級的進程,并且一個進程包含多個線程(同在一個軟件內,同時運行窗口,就是線程)

      并發和并行

      并發:同時訪問某個東西,就是并發

      并行:一起做某些事情,就是并行

      JUC下的三個包

      2019年Java大廠面試題講解(周陽) 之Volatile和JMM內存模型的可見性

      java.util.concurrent

      java.util.concurrent.atomic

      java.util.concurrent.locks

      談談對Volatile的理解

      Volatile在日常的單線程環境是應用不到的

      Volatile是Java虛擬機提供的輕量級的同步機制(三大特性)

      保證可見性

      不保證原子性

      禁止指令重排

      JMM是什么

      JMM是Java內存模型,也就是Java Memory Model,簡稱JMM,本身是一種抽象的概念,實際上并不存在,它描述的是一組規則或規范,通過這組規范定義了程序中各個變量(包括實例字段,靜態字段和構成數組對象的元素)的訪問方式

      JMM關于同步的規定:

      線程解鎖前,必須把共享變量的值刷新回主內存

      線程解鎖前,必須讀取主內存的最新值,到自己的工作內存

      加鎖和解鎖是同一把鎖

      由于JVM運行程序的實體是線程,而每個線程創建時JVM都會為其創建一個工作內存(有些地方稱為棧空間),工作內存是每個線程的私有數據區域,而Java內存模型中規定所有變量都存儲在主內存,主內存是共享內存區域,所有線程都可以訪問**,但線程對變量的操作(讀取賦值等)必須在工作內存中進行,首先要將變量從主內存拷貝到自己的工作內存空間,然后對變量進行操作,操作完成后再將變量寫會主內存,**不能直接操作主內存中的變量,各個線程中的工作內存中存儲著主內存中的變量副本拷貝,因此不同的線程間無法訪問對方的工作內存,線程間的通信(傳值)必須通過主內存來完成,其簡要訪問過程:

      數據傳輸速率:硬盤 < 內存 < < cache < CPU

      上面提到了兩個概念:主內存 和 工作內存

      主內存:就是計算機的內存,也就是經常提到的8G內存,16G內存

      工作內存:但我們實例化 new student,那么 age = 25 也是存儲在主內存中

      當同時有三個線程同時訪問 student中的age變量時,那么每個線程都會拷貝一份,到各自的工作內存,從而實現了變量的拷貝

      即:JMM內存模型的可見性,指的是當主內存區域中的值被某個線程寫入更改后,其它線程會馬上知曉更改后的值,并重新得到更改后的值。

      JMM的特性

      JMM的三大特性,volatile只保證了兩個,即可見性和有序性,不滿足原子性

      可見性

      原子性

      有序性

      可見性代碼驗證

      但我們對于成員變量沒有添加任何修飾時,是無法感知其它線程修改后的值

      package com.moxi.interview.study.thread; /** * Volatile Java虛擬機提供的輕量級同步機制 * * 可見性(及時通知) * 不保證原子性 * 禁止指令重排 * * @author: 輕狂書生 * @create: 2020-03-09-15:58 */ import java.util.concurrent.TimeUnit; /** * 假設是主物理內存 */ class MyData { int number = 0; public void addTo60() { this.number = 60; } } /** * 驗證volatile的可見性 * 1. 假設int number = 0, number變量之前沒有添加volatile關鍵字修飾 */ public class VolatileDemo { public static void main(String args []) { // 資源類 MyData myData = new MyData(); // AAA線程 實現了Runnable接口的,lambda表達式 new Thread(() -> { System.out.println(Thread.currentThread().getName() + "\t come in"); // 線程睡眠3秒,假設在進行運算 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } // 修改number的值 myData.addTo60(); // 輸出修改后的值 System.out.println(Thread.currentThread().getName() + "\t update number value:" + myData.number); }, "AAA").start(); while(myData.number == 0) { // main線程就一直在這里等待循環,直到number的值不等于零 } // 按道理這個值是不可能打印出來的,因為主線程運行的時候,number的值為0,所以一直在循環 // 如果能輸出這句話,說明AAA線程在睡眠3秒后,更新的number的值,重新寫入到主內存,并被main線程感知到了 System.out.println(Thread.currentThread().getName() + "\t mission is over"); /** * 最后輸出結果: * AAA come in * AAA update number value:60 * 最后線程沒有停止,并行沒有輸出 mission is over 這句話,說明沒有用volatile修飾的變量,是沒有可見性 */ } }

      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

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      輸出結果為

      最后線程沒有停止,并行沒有輸出 mission is over 這句話,說明沒有用volatile修飾的變量,是沒有可見性

      當我們修改MyData類中的成員變量時,并且添加volatile關鍵字修飾

      /** * 假設是主物理內存 */ class MyData { /** * volatile 修飾的關鍵字,是為了增加 主線程和線程之間的可見性,只要有一個線程修改了內存中的值,其它線程也能馬上感知 */ volatile int number = 0; public void addTo60() { this.number = 60; } }

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      最后輸出的結果為:

      主線程也執行完畢了,說明volatile修飾的變量,是具備JVM輕量級同步機制的,能夠感知其它線程的修改后的值。

      Java JVM 任務調度

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:docker 容器的網絡管理
      下一篇:銀聯支付接入對接常見問題總結
      相關文章
      亚洲最大的视频网站| 久久亚洲AV成人无码国产最大| 亚洲香蕉在线观看| 亚洲一区二区三区四区在线观看| 国产亚洲老熟女视频| 亚洲国产综合无码一区二区二三区| 亚洲熟妇久久精品| 久久亚洲精品国产精品婷婷| 精品亚洲成在人线AV无码| 亚洲va在线va天堂成人| 亚洲五月综合网色九月色| 亚洲av永久综合在线观看尤物| 亚洲国产情侣一区二区三区| 亚洲精品在线免费观看视频| 亚洲欧洲国产视频| 亚洲av片不卡无码久久| 亚洲午夜无码久久| 亚洲av无码一区二区三区在线播放| 亚洲av日韩精品久久久久久a| 极品色天使在线婷婷天堂亚洲| 国产偷国产偷亚洲高清人| 亚洲成A∨人片天堂网无码| 亚洲精品无码成人片在线观看 | 亚洲激情电影在线| 亚洲国产精品综合久久网各| 亚洲一级毛片中文字幕| 久久乐国产综合亚洲精品| 亚洲欧美中文日韩视频| 国产成人综合亚洲| 国产成人精品久久亚洲| 国产亚洲A∨片在线观看| 亚洲国产综合精品中文第一区| 色拍自拍亚洲综合图区| 亚洲免费中文字幕| 亚洲日本天堂在线| 亚洲国产精品自产在线播放| 一本色道久久综合亚洲精品| 亚洲av无码不卡一区二区三区| 久久亚洲春色中文字幕久久久| 亚洲最大在线视频| 久久亚洲精品无码av|