《深入理解java虛擬機-jvm高級特性與最佳實踐》第13章線程安全與鎖優化

概述

面向過程的編程思想

站在計算機的角度去抽象問題和解決問題,把數據和過程分別作爲獨立的部分來考慮,數據代表問題空間的中的客體,程序代碼則用於處理這些數據

面向對象的編程思想

站在現實世界的角度去抽象和解決問題,把數據和行爲都看作是對象的一部分

線程安全

線程安全的定義:

當多個線程訪問一個對象時,如果不用考慮這些線程在運行時環境下的調度和交替執行,也不需要進行額外的同步,或者在調用方進行任何其他的協調操作,調用這個對象的行爲都可以獲得正確的結果,那麼這個對象是線程安全的
                            出自<<Java Concurrency In Practice>> Brian Goetz

線程的安全與否是通過在多線程環境中對共享數據的操作來判斷的
對於這些共享數據,有以下5類,安全程序從強減弱

  • 不可變
    不可變的對象一定是線程安全的。
    說到不可變,在java中第一反應是final關鍵字。用來聲明對象在正確構造後(沒有發生this引用逃逸的情況)不能被修改。
    this引用逃逸的幾種情況是:
        在構造函數中創建內部,
        在構造函數中就把這個內部類給發佈了出去,
        在構造函數中啓動一個線程
    ps:final也可以用來保持可見性。
    java api符合不可變要求的其它類型有stringenum, Long, Double, BigInteger, BigDecimal
  • 絕對線程安全
  • 相對線程安全
  • 線程兼容
  • 線程對立
    無論調用端是否採取了同步措施,都無法在多線程環境中併發使用的代碼
    如Thread中的suspend() ,resume()
共享數據類型 調用方 調用對象
不可變 不可變 不可變
絕對線程安全 線程安全 線程安全
相對線程安全 不需要線程安全 線程安全
線程兼容 需要線程安全 非線程安全
線程對立 線程不安全 線程不安全

如何實現線程安全?

  • 互斥同步
     悲觀併發策略
     保證在同一時刻只能被一個線程使用 臨界區,互斥量和信號量 都是主要的實現方式。    
     如synchronized和ReentrantLock關鍵字 一個是原生語法層面的互斥鎖,一個是api層面的互斥鎖。
     reentrantLock的高級特性:等待可中斷,可實現公平鎖,以及鎖可以綁定多個條件。
     jdk1.6之後兩者的性能基本持平,提倡如果synchronized能實現需求的情況下,優先使用synchronized
  • 非阻塞同步
     基於衝突檢測的樂觀的併發策略
     就是先進行操作,如果沒有其他的線程爭用共享數據,那操作就成功了,如果有爭用,就用補償措施 如重試,直到成功爲止
  • 無同步方案

鎖優化

  • 自旋鎖與自適應鎖
自旋 ,因爲共享數據鎖定狀態只會持續很短的時間。爲了減少線程下上文切換帶來的性能損耗,讓當前請求線程等待,並重試請求獲取鎖。
如何開啓?
-XX:+UseSpinning   1.6之後是默認開啓的
自旋的默認次數是10次
自適應的自旋鎖
自旋重試的間隔時間及次數是由當前鎖的狀態來決定的。
個人理解:本質就是重試
  • 鎖消除
鎖消除是指虛擬機在運行時,對一些代碼上要求同步,但是被檢測到不可能存在共享數據競爭的鎖進行消除。
判斷依據來源於:逃逸分析的數據支持
個人理解:其實也就是判斷當前的數據是否是線程私有的
  • 鎖粗化
如果虛擬機探測到有一系列的操作都是對同一個對象進行加鎖解鎖,會把加鎖同步的範圍擴展到整個操作序列的外面
  • 輕量級鎖
  • 偏向鎖
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章