1. 程式人生 > >簡單比較lock和synchronized

簡單比較lock和synchronized

synchronized是基於jvm底層實現的資料同步,lock是基於Java編寫,主要通過硬體依賴CPU指令實現資料同步。下面一一介紹

一、

  1.synchronized

 優點:實現簡單,語義清晰,便於JVM堆疊跟蹤,加鎖解鎖過程由JVM自動控制,提供了多種優化方案,使用更廣泛

  缺點:悲觀的排他鎖,不能進行高階功能

  2.lock

  優點:可定時的、可輪詢的與可中斷的鎖獲取操作,提供了讀寫鎖、公平鎖和非公平鎖  

  缺點:需手動釋放鎖unlock,不適合JVM進行堆疊跟蹤

  3.相同點 

  都是可重入鎖


二、synchronized的實現方案

  1.synchronized能夠把任何一個非null物件當成鎖,實現由兩種方式:

  a.當synchronized作用於非靜態方法時,鎖住的是當前物件的事例,當synchronized作用於靜態方法時,鎖住的是class例項,又因為Class的相關資料儲存在永久帶,因此靜態方法鎖相當於類的一個全域性鎖。

  b.當synchronized作用於一個物件例項時,鎖住的是對應的程式碼塊。

  2.synchronized鎖又稱為物件監視器(object)。

      3.當多個執行緒一起訪問某個物件監視器的時候,物件監視器會將這些請求儲存在不同的容器中。

  >Contention List:競爭佇列,所有請求鎖的執行緒首先被放在這個競爭佇列中

  >Entry List:Contention List中那些有資格成為候選資源的執行緒被移動到Entry List中

  >Wait Set:哪些呼叫wait方法被阻塞的執行緒被放置在這裡

  >OnDeck:任意時刻,最多隻有一個執行緒正在競爭鎖資源,該執行緒被成為OnDeck

  >Owner:當前已經獲取到所資源的執行緒被稱為Owner

  > !Owner:當前釋放鎖的執行緒

  下圖展示了他們之前的關係

      

  4.synchronized在jdk1.6之後提供了多種優化方案:

  >自旋鎖

    jdk1.6之後預設開啟,可以使用引數-XX:+UseSpinning控制,自旋等待不能代替阻塞,且先不說對處理器數量的要求,自旋等待本身雖然避免了執行緒切換的開銷,但它是要佔用處理器時間的,因此,如果鎖被佔用的時間很短,自旋等待的效果就會非常好,反之,如果鎖被佔用的時候很長,那麼自旋的執行緒只會白白消耗處理器資源,而不會做任何有用的工作,反而會帶來效能上的浪費。自旋次數的預設值是 10 次,使用者可以使用引數 -XX:PreBlockSpin 來更改。

    自旋鎖的本質:執行幾個空方法,稍微等一等,也許是一段時間的迴圈,也許是幾行空的彙編指令。

  >鎖消除

    即時編譯器在執行時,對一些程式碼上要求同步,但是被檢測到不可能存在共享資料競爭的鎖進行消除,依據來源於逃逸分析的資料支援,那麼是什麼是逃逸分析?對於虛擬機器來說需要使用資料流分析來確定是否消除變數底層框架的同步程式碼,因為有許多同步的程式碼不是自己寫的。

例1.1

public static String concatString(String s1, String s2, String s3) {  
    return s1 + s2 + s3;  
}  

  由於 String 是一個不可變的類,對字串的連線操作總是通過生成新的 String 物件來進行的,因此 Javac 編譯器會對 String 連線做自動優化。在 JDK 1.5 之前,會轉化為 StringBuffer 物件的連續 append() 操作,在 JDK 1.5 及以後的版本中,會轉化為 StringBuilder 物件的連續 append() 操作,這裡的stringBuilder.append是執行緒不同步的(假設是同步)。

  Javac 轉化後的字串連線程式碼為:

public static String concatString(String s1, String s2, String s3) {  
    StringBuffer sb = new StringBuffer();  
    sb.append(s1);  
    sb.append(s2);  
    sb.append(s3);  
    return sb.toString();  
}  

  此時的鎖物件就是sb,虛擬機器觀察變數 sb,很快就會發現它的動態作用域被限制在 concatString() 方法內部。也就是說,sb 的所有引用永遠不會 “逃逸” 到concatString() 方法之外,其他執行緒無法訪問到它,雖然這裡有鎖,但是可以被安全地消除掉,在即時編譯之後,這段程式碼就會忽略掉所有的同步而直接執行了。

  >鎖粗化

  將同步塊的作用範圍限制得儘量小——只在共享資料的實際作用域中才進行同步,這樣是為了使得需要同步的運算元量儘可能變小,如果存在鎖競爭,那等待鎖的執行緒也能儘快拿到鎖。

  >輕量級鎖

  加鎖過程:在程式碼進入同步塊的時候,如果此同步物件沒有被鎖定(鎖標誌位為 “01” 狀態)虛擬機器首先將在當前執行緒的棧幀中建立一個名為鎖記錄(Lock Record)的空間,用於儲存鎖物件目前的 Mark Word 的拷貝,這時候執行緒堆疊與物件頭的狀態如圖 13-3 所示

   

  然後,虛擬機器將使用 CAS 操作嘗試將物件的 Mark Word 更新為指向 Lock Record 的指標。如果這個更新動作成功了,那麼這個執行緒就擁有了該物件的鎖,並且物件 Mark Word 的鎖標誌位 (Mark Word 的最後 2bit)將轉變為 “00”,即表示此物件處於輕量級鎖定狀態,這時執行緒堆疊與物件頭的狀態如圖13-4                

  如果上述更新操作失敗,則說明這個鎖物件被其他鎖佔用,此時輕量級變為重量級鎖,標誌位為“10”,後面等待的執行緒進入阻塞狀態。

  解鎖過程:也是由CAS進行操作的,如果物件的 Mark Word 仍然指向著執行緒的鎖記錄,那就用 CAS 操作把物件當前的 Mark Word 和執行緒中複製的 Displaced Mark Word 替換回來,如果替換成功,整個同步過程就完成了。如果替換失敗,說明有其他執行緒嘗試過獲取該鎖,那就要釋放鎖的同時,喚醒被掛起的執行緒。

  輕量級鎖能提升程式同步效能的依據是 “對於絕大部分的鎖,在整個同步週期內都是不存在競爭的”,這是一個經驗資料。如果沒有競爭,輕量級鎖使用 CAS 操作避免了使用互斥量的開銷,但如果存在鎖競爭,除了互斥量的開銷外,還額外發生了 CAS 操作,因此在有競爭的情況下,輕量級鎖會比傳統的重量級鎖更慢。

  >偏向鎖

  偏向鎖也是 JDK 1.6 中引入的一項鎖優化,它的目的是消除資料在無競爭情況下的同步原語,進一步提高程式的執行效能。如果說輕量級鎖是在無競爭的情況下使用 CAS 操作去消除同步使用的互斥量,那偏向鎖就是在無競爭的情況下把整個同步都消除掉,連 CAS 操作都不做了。

  實質就是設定一個變數,判斷這個變數是否是當前執行緒,是就避免再次加鎖解鎖操作,從而避免了多次的CAS操作。壞處是如果一個執行緒持有偏向鎖,另外一個執行緒想爭用偏向物件,擁有者想釋放這個偏向鎖,釋放會帶來額外的效能開銷,但是總體來說偏向鎖帶來的好處還是大於CAS的代價的。在具體問題具體分析的前提下,有時候使用引數 -XX:-UseBiasedLocking 來禁止偏向鎖優化反而可以提升效能。

三、lock的實現方案

與synchronized不同的是lock是純java手寫的,與底層的JVM無關。在java.util.concurrent.locks包中有很多Lock的實現類,常用的有ReenTrantLock、ReadWriteLock(實現類有ReenTrantReadWriteLock)

,其實現都依賴java.util.concurrent.AbstractQueuedSynchronizer類(簡稱AQS),實現思路都大同小異,因此我們以ReentrantLock作為講解切入點。

分析之前我們先來花點時間看下AQS。AQS是我們後面將要提到的CountDownLatch/FutureTask/ReentrantLock/RenntrantReadWriteLock/Semaphore的基礎,因此AQS也是Lock和Excutor實現的基礎。它的基本思想就是一個同步器,支援獲取鎖和釋放鎖兩個操作。

  

要支援上面鎖獲取、釋放鎖就必須滿足下面的條件:

  1、  狀態位必須是原子操作的

  2、  阻塞和喚醒執行緒

  3、  一個有序的佇列,用於支援鎖的公平性

  場景:可定時的、可輪詢的與可中斷的鎖獲取操作,公平佇列,或者非塊結構的鎖。

  主要從以下幾個特點介紹:

  1.可重入鎖

    如果鎖具備可重入性,則稱作為可重入鎖。像synchronized和ReentrantLock都是可重入鎖,可重入性在我看來實際上表明瞭鎖的分配機制:基於執行緒的分配,而不是基於方法呼叫的分配。

  2.可中斷鎖

    可中斷鎖:顧名思義,就是可以相應中斷的鎖。

    在Java中,synchronized就不是可中斷鎖,而Lock是可中斷鎖。

    如果某一執行緒A正在執行鎖中的程式碼,另一執行緒B正在等待獲取該鎖,可能由於等待時間過長,執行緒B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的執行緒中中斷它,這種就是可中斷鎖。

  3.公平鎖和非公平鎖

     公平鎖以請求鎖的順序來獲取鎖,非公平鎖則是無法保證按照請求的順序執行。synchronized就是非公平鎖,它無法保證等待的執行緒獲取鎖的順序。而對於ReentrantLock和ReentrantReadWriteLock,它預設情況下是非公平鎖,但是可以設定為公平鎖。

    引數為true時表示公平鎖,不傳或者false都是為非公平鎖。

ReentrantLock lock = new ReentrantLock(true);

  4.讀寫鎖

  讀寫鎖將對一個資源(比如檔案)的訪問分成了2個鎖,一個讀鎖和一個寫鎖。

  正因為有了讀寫鎖,才使得多個執行緒之間的讀操作不會發生衝突。

  ReadWriteLock就是讀寫鎖,它是一個介面,ReentrantReadWriteLock實現了這個介面。

  可以通過readLock()獲取讀鎖,通過writeLock()獲取寫鎖。

相關推薦

簡單比較locksynchronized

synchronized是基於jvm底層實現的資料同步,lock是基於Java編寫,主要通過硬體依賴CPU指令實現資料同步。下面一一介紹一、  1.synchronized 優點:實現簡單,語義清晰,便於JVM堆疊跟蹤,加鎖解鎖過程由JVM自動控制,提供了多種優化方案,使用更廣泛  缺點:悲觀的排他鎖,不能進

(轉)Locksynchronized比較詳解

今天看了併發實踐這本書的ReentantLock這章,感覺對ReentantLock還是不夠熟悉,有許多疑問,所有在網上找了很多文章看了一下,總體說的不夠詳細,重點和焦點問題沒有談到,但這篇文章相當不錯,說的很全面,主要的重點都說到了,所有在這裡轉載了這篇文章,注意紅色字型。

Locksynchronized使用

bject adl 每次 .get shm runnable start new while 該文章主要講解如何快速應用Lock和synchronized 讀者可以自行學習Lock和synchronized系統級比較;可參考並發實戰等,自己決定什麽場景下使有哪種鎖 Lo

Locksynchronized的選擇

OS 意思 獲得 通過 interrupt body 釋放 中斷 大量 學習資源:http://www.cnblogs.com/dolphin0520/p/3923167.html 一.java.util.concurrent.locks包下常用的類 1.Lock publ

lock synchronized 的區別

異常 做了 -s ive 遇到 bsp 加鎖 競爭 主動 1 lock是接口實現,synchronized是內置方法native實現 2 lock可以主動釋放鎖,synchronized只能是加鎖的代碼塊執行完畢或者遇到異常退出被動的釋放鎖 3 性能方面,如果競爭資源不是

thread中sleepwait方法的區別,以及locksynchronized的區別

最近在專案中設計業務請求邏輯這一塊,運用到了thread的一些知識,所以就又去特定的研究了一下! 首先 sleep和wait的區別: 1、我們通過檢視原始碼得知,sleep是Threa的靜態方法,而wait方法是Object的成員方法; 2、sleep沒有synchnori

簡單比較 BeautifulSoup Xpath 的效能

一些說明 我為什麼要寫這篇文章?   其實這篇文章並不是為了比較出結論,因為結論是顯而易見的,Xpath 必然 是要比 BeautifulSoup 在時間和空間上都要效能更好一些。其中理由有很多,其中一個很明顯的是 BeautifulSoup 在構建一個物

關於locksynchronized的選擇

dwr 實現 fin 進行 java finall code 使用 可能 這裏不介紹具體用法,介紹lock和synchronized的不同從而做出選擇 1.lock是一個接口,而synchronized是java中的一個關鍵字,synchronized是內置的語言實現。

咀嚼LockSynchronized

## 1.Synchronized鎖 底層是`monitor`監視器,每一個物件再建立的時候都會常見一個`monitor`監視器,在使用`synchronized`程式碼塊的時候,會在程式碼塊的前後產生一個`monitorEnter和monitorexit`指令,來標識這是一個同步程式碼塊。 #### 1

mysqlOracle的簡單比較

空值 localhost pda varchar2 自連接 smi ins 修改字段 條件 ORA-27101: shared memory realm does not exist解決方法: 1、用CMD進入命令行2、sqlplus /nolog3、conn / as s

angular4.0angularJS、react.js、vue.js的簡單比較

width 文檔 個人 過程 處理 特性 很好 單頁應用 兼容 angularJS特性 模板功能強大豐富(數據綁定大大減少了代碼量) 比較完善的前端MVC框架(只要學習這個框架,按照規定往裏面填東西就可以完成前端幾乎所有的的問題) 引入了Java的一些概念 angu

集中式(SVN)分布式(Git)版本控制系統的簡單比較

ron table targe 特點 相對 tps ble 12px pan 集中式(SVN) 分布式(Git) 是否有中央服務器 有。開發人員需要從中央服務器獲得最新版本的項目然後在本地開發,開發完推送給中央服務器。因此脫離服

關於DHRSA算法的簡單比較

加解密 RSA算法 DH算法 本文簡單地談下關於安全中最為常用的兩個非對稱加密的DH算法及RSA算法,文中無意於涉及一些數學原理,這個在網上已經有很多文章敘述了,再重復也沒有太多意思(這類文章只要關註兩點,**其一是密鑰生成方法,其二就是數據的加解密公式**),此文僅僅是幫助一般用戶能夠明確

多執行緒之Locksynchronized比較及使用

   第一:先比較兩者的區別: 類別 synchronized

Java CAS synchronized Lock

CAS 機制 適用場景:樂觀認為併發不高,不需要阻塞,可以不上鎖。 特點:不斷比較更新,直到成功。 缺點:高併發cpu壓力大;ABA問題。 ABA問題: CAS機制生效的前提是,取出記憶體中

cookie session的簡單比較

1、cookie資料存放在客戶的瀏覽器上,session資料放在伺服器上。 2、cookie不是很安全,別人可以分析存放在本地的COOKIE並進行COOKIE欺騙   考慮到安全應當使用session。 3、session會在一定時間內儲存在伺服器上。當訪問增多,會比較佔用你伺服器的效

intInteger的簡單比較

int與Integer的區別  1、屬於四類八種基本型別中的一種,用int 宣告的變數是非物件型別,即不能在其上呼叫方法。Integer是一個類(包裝類),用Integer宣告變數其實一個物件型別(或者是一個引用型別) 2、“==”作用於基本型別時比較的是基本型別的值,作用於物件上

說說markdownlatex的簡單比較

latex是純學術風格,寫paper寫書用 markdown是程式設計師風格,寫筆記貼程式碼片段用 簡單說,latex適合長篇、精緻,比如數學公式、圖片位置調整、表格樣式調整。而markdown

python list/tuple/dict/set/deque的簡單比較、優化時間複雜度

一、關於增刪改查序列listtupledictsetdeque能否增加元素√×√√√是否有序√√××√能否刪除√×√√√可否雜湊×√√√×序列listtupledictsetdeque增加方法append、extend、insert×updateadd、updateappen

簡單比較init-method,afterPropertiesSetBeanPostProcessor

一、簡單介紹 1、init-method方法,初始化bean的時候執行,可以針對某個具體的bean進行配置。init-method需要在applicationContext.xml配置文件中bean的定義裡頭寫明。例如:這樣,當TestBean在初始化的時候會執行TestBean中定義的init方法。2、af