Java內存模型(JMM)主要目標是定義多線程的狀況下線程訪問變量的規則。java
JMM規定線程之間的共享變量存儲在主內存中,每一個線程都有一個本地內存(工做內存),本地內存存儲了共享變量的副本。安全
什麼是線程安全問題?多線程
當多個線程同時共享同一個全局變量作寫的操做時候,可能會受到其餘線程的干擾,致使數據髒讀。(數據一致性問題)性能
如何解決線程安全問題?線程
核心思想:在同一時刻,只能有一個線程執行。對象
經過加鎖使線程更加安全,也使程序的執行效率更低。blog
衡量線程安全的3個要素:排序
volatile是一種輕量級的同步機制,能夠保證可見性【及時將修改的變量刷新到主內存中】,但不能保證原子性,而且禁止重排序。遞歸
volatile在多線程下的適用場景:一寫多讀事務
volatile如何保證內存可見性?
當一個線程對volatile修飾的變量進行寫操做時,該線程中的本地內存的變量會被馬上刷新到主內存中。
當一個線程對volatile修飾的變量進行讀操做時,該線程直接讀取主內存的變量。
volatile可否保證線程安全?
不能,保證線程安全須要同時具有原子性,可見性和有序性。而volatile只能保證可見性和有序性,沒法保證原子性。
核心思想:在多線程執行同一個方法時,只有獲取到鎖,才能進入方法裏面執行
使用方式:
輕量級鎖:手動上鎖解鎖,擴展性強。表明:Lock
重量級鎖:自動上鎖解鎖,封裝程度高。表明:Synchronized
可重入鎖(遞歸鎖):當一個線程已經獲取到鎖後,再次請求該鎖,就可直接獲取。(鎖的傳遞,鎖的嵌套)表明:Synchronized,Lock
鎖的可重入性避免了大部分死鎖狀況的產生
不可重入鎖:不具有傳遞性
ReentrantReadWriteLock
相對Synchronized效率更高,但在多線程狀況下,只支持讀讀共存,不支持讀寫,寫寫。
思想:認爲不會發生線程衝突(本質上是沒有鎖的)
執行流程,先讀取數據,而後在更新前檢查在讀取至更新這段時間數據是否被修改
爲何樂觀鎖適合多讀場景?
樂觀鎖是一種更新前的檢查機制,相對於悲觀鎖來講在多讀場景下能夠減小鎖的性能開銷,對於多寫場景,樂觀鎖會一直進入已修改,從新讀取,再次提交的循環,反而帶來更多的資源消耗。
思想:認爲必定會發生線程衝突
執行流程:讀取數據的時候上鎖(其餘用戶沒法讀取),直到本次數據更新完成纔會釋放鎖。在多寫場景下,能保證較高的數據一致性。
【總的來講,樂觀鎖回滾重試,悲觀鎖阻塞事務】
原子類:AtomicBoolean,AtomicInteger,AtomicLong,AtomicReference可保證線程安全,底層使用CAS無鎖機制
CAS:Compare and Swap,比較再交換,屬於樂觀鎖的一種
CAS原理
CAS包含3個參數,CAS(V,E,N),V:主內存的變量值,E:本地內存修改前的值,N:本地內存修改後的值
比較主內存的值和本地內存修改前的值是否一致,若一致,將修改後的值刷新到主內存,若不一致,當前線程放棄更新,將主內存數據刷新到本地內存,再次重試。
優勢:非阻塞,不會發生死鎖狀況,效率更高
缺點:ABA問題(能夠經過加入版本號來區分變量是否被修改)