關於Java併發編程之美,你瞭解嗎?

之前的文章有提到過“高併發”的問題,那麼今天我們就來好好說說Java併發編程與高併發基礎概念吧~

關於Java併發編程之美,你瞭解嗎?

併發與高併發基本概念

併發:同時擁有兩個或者多個線程,如果程序在單核處理器上運行,多個線程將交替地換入或者換出內存,這些線程是同時“存在”的,每個線程都處於執行過程中的某個狀態,如果運行在多核處理器上,此時,程序中的每個線程都將分配到一個處理器核上,因此可以同時運行。

高併發:高併發(High Concurrency)是互聯網分佈式系統架構設計中必須考慮的因素之一,它通常是指,通過設計保證系統能夠同時並行處理很多請求。

注:

併發:多個線程操作相同的資源,保證線程安全,合理使用資源

高併發:服務器能同時處理很多請求,提高程序性能

關於Java併發編程之美,你瞭解嗎?

CPU多級緩存-緩存一致性

CPU多級緩存

關於Java併發編程之美,你瞭解嗎?

為什麼需要CPU cache

CPU的頻率太快了,快到主存跟不上,這樣在處理器時鐘週期內,CPU常常需要等待主存,浪費資源。所以cache的出現,是為了緩解CPU和內存之間速度的不匹配問題(結構:CPU -> cache -> memory)。

CPU cache有什麼意義

時間局部性:如果某個數據被訪問,那麼在不久的將來它很可能被再次訪問;

空間局部性:如果某個數據被訪問,那麼與它相鄰的數據很快也可能被訪問。

緩存一致性(MESI)

用於保證多個CPU cache之間緩存共享數據的一致性

關於Java併發編程之美,你瞭解嗎?

MESI協議中的狀態

  • M——Modified 修改:指的是該緩存行只被緩存在該CPU的緩存中,並且是被修改過的,因此他與主存中的數據是不一致的,該緩存行中的數據需要在未來的某個時間點(允許其他CPU讀取主存相應中的內容之前)寫回主存,然後狀態變成E(獨享)
  • E——Exclusive 獨享:指的是該緩存行只被緩存在該CPU的緩存中,是未被修改過的,與主存的數據是一致的,可以在任何時刻當有其他CPU讀取該內存時,變成S(共享)狀態,當CPU修改該緩存行的內容時,變成M(被修改)的狀態
  • S——Share 共享:意味著該緩存行可能會被多個CPU進行緩存,並且該緩存中的數據與主存數據是一致的,當有一個CPU修改該緩存行時,其他CPU是可以被作廢的,變成I(無效的)
  • I——Invalid 無效:代表這個緩存是無效的,可能是有其他CPU修改了該緩存行
  • local read:讀本地緩存的數據
  • local write:將數據寫到本地緩存裡面
  • remote read:將內存中的數據讀取到緩存中來
  • remote write:將緩存中的數據寫會到主存裡面
關於Java併發編程之美,你瞭解嗎?

CPU多級緩存-亂序執行優化

處理器為提高運算速度而作出違背代碼原有順序的優化

關於Java併發編程之美,你瞭解嗎?

JAVA內存模型

Java 內存模型

關於Java併發編程之美,你瞭解嗎?

  • Heap(堆):java裡的堆是一個運行時的數據區,堆是由垃圾回收來負責的,堆的優勢是可以動態的分配內存大小,生存期也不必事先告訴編譯器,因為他是在運行時動態分配內存的,java的垃圾回收器會定時收走不用的數據,缺點是由於要在運行時動態分配,所以存取速度可能會慢一些。
  • Stack(棧):棧的優勢是存取速度比堆要快,僅次於計算機裡的寄存器,棧的數據是可以共享的,缺點是存在棧中的數據的大小與生存期必須是確定的,缺乏一些靈活性。棧中主要存放一些基本類型的變量,比如 int,short,long,byte,double,float,boolean,char,對象句柄。

java內存模型要求調用棧和本地內存變量存放在線程棧(Thread Stack)上,對象存放在堆上。一個本地變量可能存放一個對象的引用,這時引用變量存放在本地棧上,但是對象本身存放在堆上,成員變量跟隨著對象存放在堆上,而不管是原始類型還是引用類型,靜態成員變量跟隨著類的定義一起存在在堆上。存在堆上的對象,可以被持有這個對象的引用的線程訪問。如果兩個線程同時訪問同一個對象的私有變量,這時他們獲得的是這個對象的私有拷貝。

計算機硬件架構

關於Java併發編程之美,你瞭解嗎?

JVM 與硬件內存架構的關聯

關於Java併發編程之美,你瞭解嗎?

Java內存模型抽象結構

關於Java併發編程之美,你瞭解嗎?

Java內存模型-同步八種操作

  • lock(鎖定):作用於主內存的變量,把一個變量標識為一條線程獨佔狀態
  • unlock(解鎖):作用於主內存的變量,把一個處於鎖定狀態的變量釋放出來,釋放後的變量才可以被其他線程鎖定
  • read(讀取):作用於主內存的變量,把一個變量值從主內存傳輸到線程的工作內存中,以便隨後的load動作使用
  • load(載入):作用於工作內存的變量,它把read操作從內存中得到的變量值放入工作內存的變量副本中
  • use(使用):作用於工作內存的變量,把工作內存中的一個變量值傳遞給執行引擎
  • assign(賦值):作用於工作內存的變量,它把一個從執行引擎接收到的值賦值給工作內存的變量
  • store(存儲):作用於工作內存的變量,把工作內存中的一個變量的值傳送到主內存中,以便隨後的write的操作
  • write(寫入):作用於主內存的變量,它把store操作從工作內存中的一個變量的值傳送到主內存的變量中

Java內存模型-同步規則

  • 如果要把一個變量從主內存中複製到工作內存,就需要按順序地執行read和load操作,如果把變量從工作內存中同步回主內存中,就要按順序地執行store和write操作。但Java內存模型只要求上述操作必須按順序執行,而沒有保證必須是連續執行
  • 不允許read和load、store和write操作之一單獨出現
  • 不允許一個線程丟棄它的最近assign操作,即變量在工作內存中改變了之後必須同步到主內存中
  • 不允許一個線程無原因地(沒有發生過任何assign操作)把數據從工作內存同步回主內存中
  • 一個新的變量只能再主內存中誕生,不允許在工作內存中直接使用一個未被初始化(load或assign)的變量。即就是對一個變量實施use和store操作之前,必須先執行過了assign和load操作
  • 一個變量在同一時刻只允許一條線程對其進行lock操作,但lock操作可以被同一條線程重複執行多次,多次執行lock後,只有執行相同次數的unlock操作,變量才會被解鎖。lock和unlock必須成對出現
  • 如果對一個變量執行lock操作,將會清空工作內存中此變量的值,在執行引擎使用這個變量前需要重新執行load或assign操作初始化變量的值
  • 如果一個變量事先沒有被lock操作鎖定,則不允許對它執行unlock操作;也不允許去unlock一個被其他線程鎖定的變量
  • 對一個變量執行unlock操作之前,必須先把此變量同步到主內存中(執行store和write操作)

Java內存模型-同步操作與規則

關於Java併發編程之美,你瞭解嗎?

併發的優勢與風險

優點

  • 速度:同時處理多個請求,響應更快;複雜的操作可以分成多個進程同時進行
  • 設計:程序設計在某些情況下更簡單,也可以有更多的選擇
  • 資源利用:CPU能夠在等待IO的時候做一些其他的事情

缺點

  • 安全性:多個線程共享數據時可能會產生於期望不相符的結果
  • 活躍性:某個操作無法繼續進行下去時,就會發生活躍性問題,比如死鎖、飢餓等問題
  • 性能:線程過多時會使得:CPU頻繁切換,調度時間增多,同步機制,消耗過多內存


關於Java併發編程之美,你瞭解嗎?


今天我們的文章就到這了,小夥伴對於併發編程與高併發有沒有進一步的認識呢?如果你還有更多的疑問,歡迎在文章下方留言


分享到:


相關文章: