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

歡迎訪問 生活随笔!

生活随笔

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

java

反骨之Java是如何解决并发中的可见性问题的

發布時間:2023/12/8 java 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 反骨之Java是如何解决并发中的可见性问题的 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

前言

前段時間筆者寫過一篇關于, 關于《反骨之Java是如何解決并發中的原子性問題》的博文。

其中,提出一個觀點:Java中使用互斥鎖和CAS解決了并發中的原子性問題。

那么,本篇博文則主要探討的是:

Java中如何利用Java內存模型規范中的Volatile、synchronized、final關鍵字解決可見性問題。

(想自學習編程的小伙伴請搜索圈T社區,更多行業相關資訊更有行業相關免費視頻教程。完全免費哦!)

正文

在開始重點之前,我們注意到上文提到的兩個關鍵詞,即內存模型和可見性問題。

由于筆者在《反骨之硬件&軟件為Java并發編程中挖的坑(可見性&原子性&有序性)》一文中,對可見性僅是一筆帶過,所在筆者認為在本篇博文中,需要對可見性進行更進一步的解釋。

所以,在談解決可見性問題之前,我們需要聊聊可見性問題&Java內存模型。

什么是可見性問題呢?

  • 可見性,主要強調一個線程對某個共享變量進行更新之后,后續訪問該共享變量的線程可能無法立即讀取到更新后的最新結果,甚至永遠也無法得知其他線程對該共享變量進行過修改操作。那么,這種問題,我們可以稱其為:可見性問題。

當然,可見性問題是也是線程安全性的表現形式之一。

線程安全性的表現形式,即為:原子、有序、可見性。

什么是Java內存模型(JMM)?

  • 簡單來說,Java內存模型是一組規范,這些規范告訴JVM如何解決原子性、有序性和可見性問題。

我們知道Java的對象一般是放在堆內存中的,而堆內存是線程共享的,所以Java內存模型的影響范圍一般只涉及堆內存。這里,JMM有一張比較形象的圖1-1:

我們可以看到,JMM處于線程和主內存中間,充當中介人的角色。

當線程和主內存只能通過JMM通信的時候,那么JMM就是唯一的主宰!

接下來是JMM的自我介紹:

大家好,我叫Java memory model(JMM)
為了更好的解決并發編程中的線程安全性問題,即保證并發中的原子性、有序性和可見性。
所以,我規定了以下規則。
規則一:每個線程都有獨立的工作內存, 即工作內存(本地線程)
規則二:所有的共享變量都必須在主內存中, 且只能通過JMM進行控制訪問。
規則三:所有的共享變量都必須在主內存中,每個線程都有自己的工作內存(本地內存),線程的所有操作都必須在工作內存中進行,而不能直接對主內存進行操作。
規則四:工作內存之間禁止互相訪問。

掌握絕對權力之后,那么JMM就可以制定可見性規范:

比如:當線程A想跟線程B通信的時候

  • 首先,線程A需要把自己本地內存中更新后的共享變量副本,刷新到主內存中。
  • 隨后,線程B跳過讀取本地內存,直接向主內存中讀取共享變量的值,將主內存中讀取的值放入自己的本地內存中。

從這里可以看出,JMM是通過控制主內存和每個線程的本地內存之間的交互,來達到可見性目的的。

眾所周知,JMM是一組抽象的復雜的規范,那么如何把抽象的、復雜的規范變成現實可用的方法呢?

所以,Java到底是利用什么手段或措施,保證多線程環境下,共享變量是立即可見性的(鎖&volatile&final)。

  • 手段一:synchronized或Lock——互斥鎖

在并發編程中,一旦使用互斥鎖,一般能解決所有并發問題!

所以,可見性可以使用互斥鎖進行保障。

  • 手段二:volatile關鍵字

在這里筆者并不講volitale的底層實現原理,具體的底層實現細節筆者會單獨寫一篇博文來進行介紹。

其實,被volitale關鍵字修飾的共享變量,具有兩個語義(這里的語義,可以理解為潛規則)。

  • 語義一:保證可見性。即,保證線程對共享變量的修改,對其他線程是立即可見的。

volatile關鍵字保證立即可見,其中有幾點需要注意:

其一,使用volatile關鍵字會強制將修改的值(共享變量)立即寫/讀入主內存。

如何實現強制寫入主內存?

在圖1-1中我們可以看到存在線程A和線程B。那么,當線程A對共享變量進行修改的時候,會導致線程B工作內存中的共享變量副本失效。

如何實現強制讀取主內存?

一旦線程工作內存中的共享變量副本失效,那么就必須重新從主內存中讀取最新的值。

當然,看到這里相信讀者們已經看出來了,volitale的語義一是利用緩存一致性協議(MESI)來保證的。

  • 語義二:保證有序性。

額…好像保證有序性在本篇博文,出現地有點不合時宜。

反正,讀者們只需要記住:

volitale關鍵字利用禁止指令重排序和禁止編譯優化,保證有序性。

  • 手段三:final關鍵字

有final修飾的變量(基本類型)具有不可變性,當且僅有一次賦值,一旦賦值即不可變。

不可變的變量或對象,我們可以稱其為線程安全變量/對象。

因為,final關鍵字修飾的變量是不可變的,在多線程環境中不管怎么操作,都是同一個值。

所以,final關鍵字是保證可見性的手段之一。

總結

  • Java內存模型也稱為內存一致性模型,是一些復雜規范的抽象集合,其中規定了工作內存和主內存的概念。

  • volitale關鍵字具有兩種語義:保證可見性&有序性。

  • final關鍵字意味著不可變(基本數據類型byte, int……),所以在多線程環境下是立即可見的。

  • synchronized、volitale、final三個關鍵字,可以看做是Java內存模型對可見性問題提出的解決方案。

總結

以上是生活随笔為你收集整理的反骨之Java是如何解决并发中的可见性问题的的全部內容,希望文章能夠幫你解決所遇到的問題。

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