筆記來源:
【IMOOC】Java併發編程與高併發解決方案
併發基礎
綜述:html
- CPU多級緩存:緩存一致性、亂序執行優化
- Java內存模型:JMM規定、抽象結構、同步八種操做及規則
- Java併發的優點與風險
併發與高併發基本概念
基本概念
併發:同時擁有兩個或者多個線程,若是程序在單核處理器上運行,多個線程將交替地換入或者換出內存,這些線程是同時「存在」的,每一個線程都處於執行過程當中的某個狀態,若是運行在多核處理器上,此時,程序中的每一個線程都將分配到一個處理器核上,所以能夠同時運行。java
高併發:高併發(High Concurrency)是互聯網分佈式系統架構設計中必須考慮的因素之一,它一般是指,經過設計保證系統可以同時並行處理不少請求。編程
- 併發:多個線程操做相同的資源,保證線程安全,合理使用資源
- 高併發:服務器能同時處理不少請求,提升程序性能
知識技能
- 整體架構:Spring Boot、Maven、JDK八、MySQL
- 基礎組件:Mybatis、Guava、Lombok、Redis、Kafka
- 高級組件/類:Joda-Time、Atomic包、J.U.C、AQS、ThreadLocal、RateLimiter、Hystrix、threadPool、shardbatis、curator、elastic-job...
CPU多級緩存-緩存一致性
CPU多級緩存

- 爲何須要CPU cache:CPU的頻率太快了,快到主存跟不上,這樣在處理器時鐘週期內,CPU經常須要等待主存,浪費資源。因此cache的出現,是爲了緩解CPU和內存之間速度的不匹配問題(結構:CPU -> cache -> memory)。
-
CPU cache有什麼意義:緩存
- 時間局部性:若是某個數據被訪問,那麼在不久的未來它極可能被再次訪問;
- 空間局部性:若是某個數據被訪問,那麼與它相鄰的數據很快也可能被訪問。
緩存一致性(MESI)
用於保證多個CPU cache之間緩存共享數據的一致性安全

-
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:將緩存中的數據寫會到主存裏面
CPU多級緩存-亂序執行優化
- 處理器爲提升運算速度而做出違背代碼原有順序的優化
JAVA內存模型(Java Memory Model,JMM)
Java 內存模型

- Heap(堆):java裏的堆是一個運行時的數據區,堆是由垃圾回收來負責的,堆的優點是能夠動態的分配內存大小,生存期也沒必要事先告訴編譯器,由於他是在運行時動態分配內存的,java的垃圾回收器會定時收走不用的數據,缺點是因爲要在運行時動態分配,因此存取速度可能會慢一些。
- Stack(棧):棧的優點是存取速度比堆要快,僅次於計算機裏的寄存器,棧的數據是能夠共享的,缺點是存在棧中的數據的大小與生存期必須是肯定的,缺少一些靈活性。棧中主要存放一些基本類型的變量,好比 int,short,long,byte,double,float,boolean,char,對象句柄。
java內存模型要求調用棧和本地內存變量存放在線程棧(Thread Stack)上,對象存放在堆上。一個本地變量可能存放一個對象的引用,這時引用變量存放在本地棧上,可是對象自己存放在堆上,成員變量跟隨着對象存放在堆上,而不論是原始類型仍是引用類型,靜態成員變量跟隨着類的定義一塊兒存在在堆上。存在堆上的對象,能夠被持有這個對象的引用的線程訪問。若是兩個線程同時訪問同一個對象的私有變量,這時他們得到的是這個對象的私有拷貝。
計算機硬件架構

JVM 與硬件內存架構的關聯

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內存模型-同步操做與規則

併發的優點與風險
