1. 程式人生 > 程式設計 >談一談鎖

談一談鎖

公平鎖/非公平鎖

  1. 公平鎖指的是按照請求鎖的順序來分配鎖。
  2. 非公平當然就是不按申請鎖的順序分配鎖,當然這就有可能造成飢餓現象。
  3. ReentrantLock可以通過構造來指定該鎖是否是公平鎖,其內部是通過AQS來實現執行緒排程,所以能夠成為公平鎖。預設是非公平鎖,這將能夠提高它的吞吐量。
  4. synchronized是非公平鎖,因為不像Reentrantlock能通過AQS來實現執行緒排程所以它並不能成為一種公平鎖。

可重入鎖

  1. 顧名思義,當一個執行緒獲取了某個鎖之後,能再次獲得該鎖。
  2. 執行緒又去幹其他事情或者暫停掉,鎖不會釋放
  3. synchronized就是重入鎖在Java中的一個重要實現。
  4. 說下可重入鎖怎麼避免死鎖的,先看個例子
//在同一物件中有
synchronized void outerEnter() throws Exception{
    innerEnter();
}
synchronized void innerEnter() throws Exception{
  //do something
}
複製程式碼
  • 解析:
    1. 在上面的程式碼中我們先呼叫outerEnter()方法,獲得此物件的監視鎖(這裡不懂這個鎖的可以跳轉到傳送門
    2. 在這個方法中我們又去呼叫了另外一個被synchronized修飾的innerEnter()方法,這裡會再次去獲取這個物件的監視鎖注意:這裡是同一把鎖
    3. 這裡假設一種情況,如果沒有重入鎖這一特性,表現為互斥的時候,當我在獲取鎖的情況下再次去獲得同一把鎖的時候,我需要去等待這個這個鎖的釋放,但是我自己同時又持有這把鎖,所以我永遠也等不到我期望的鎖,從而形成死鎖
    4. 在這裡其實是破壞了死鎖形成條件之一的 互斥條件從而很好地避免了死鎖

獨享與共享鎖

  1. 獨享鎖指的是同一時間,一個鎖只能被單個執行緒鎖擁有,體現互斥性。反之,共享鎖就是能被多個執行緒鎖所擁有。
  2. 拿mysql的讀寫鎖來舉例:當對資料進行讀取的時候,使用的是共享鎖,其他事務需要讀取時候加上共享鎖就能實現讀取了。 3.資料行上只要還存在一個讀鎖就說明還有其他事務在讀取,不能修改,也就不能給它加寫鎖 -- 獨享鎖。

樂觀和悲觀鎖

  1. 叫它樂觀鎖就是我們對一個資料進行修改的時候,它樂觀地認為這個資料在我們將它讀下來->修改掉->返回存入的這個階段中是不會被其他併發操作修改的,所以沒必要以上來就給這個資料加一把互斥鎖。
  2. 反之,悲觀鎖就認為你去修改一個資料,那麼它一檔會被其他併發操作所修改,所以我必須給它加上一把鎖,才能保證資料的準確性。
  3. Java中的CAS(compare and swap)就屬於一種樂觀鎖,也就是不加某種特定的鎖,而悲觀鎖就是給資料加上一把鎖,無論這個鎖是什麼鎖。
  4. 再說說它們的應用場景吧:樂觀鎖適用於讀操作非常多的情況,因為我在讀的時候避免了加鎖,釋放鎖,極大地提高了效能。悲觀鎖就適用於寫操作很多的情況。
  5. 拿mysql中維持表的樂觀鎖來舉例,在mysql的表中,要有一個ObjectVersionNumber的欄位,其實這就是一種樂觀鎖。在取資料時,我們不用管直接讀取就是了。在修改資料時,我們每修改一次資料就把ObjectVersionNumber欄位加1,如果有兩個事務同時對一個資料進行操作了,其一個事務提交,修改完成,另一個提交時,發現我上次取出來的ObjectVersionNumber和現在資料庫裡面的資料不一致了,說明有人改過,所以我這次執行的事務就會失敗。從而保證了資料的準確性。

分段鎖

  1. 分段鎖指的是一組資料,對它進行多次分割,對單獨分割出來的每一塊加鎖。但需要對資料進行操作時,對當前訪問的這一塊進行單獨加鎖,其他訪問其他塊的事務就不會被阻塞掉,相應地就能提高操作效率。
  2. ConcurrentHashMap就是分段鎖在Java中的重要實現 -- 後面我會寫ConcurrentHashMap的內容敬請期待。

最後講一下Java1.5後鎖的升級與降級

  1. 其中主要涉及到是針對Synchronized的三個型別的鎖狀態 -- 偏向鎖、輕量級鎖、重量級鎖。
  2. 鎖狀態是通過物件監視器在物件頭中的欄位來指示的。
  3. 先是偏向鎖,它是指一段同步程式碼一直被一個執行緒所訪問,沒有其他的併發操作,那麼該執行緒會自動獲取鎖。降低獲取鎖的代價。
  4. 輕量級鎖是指當鎖是偏向鎖的時候,被另一個執行緒所訪問,就出現了鎖的競爭,鎖iu會升級為輕量級鎖,其他執行緒會通過自旋的形式嘗試獲取鎖,不會阻塞,提高效能。這裡自旋是指獲取鎖的執行緒不會立即阻塞,而是採用迴圈的方式去嘗試獲取鎖,這樣的好處是減少執行緒上下文切換的消耗,沒必要轉到重量級鎖。
  5. 重量級鎖是指當鎖為輕量級鎖的時候,另一個執行緒雖然是自旋,但自旋不會一直持續下去,當自旋一定次數的時候,還沒有獲取到鎖,就會進入阻塞,該鎖膨脹為重量級鎖。重量級鎖會讓其他申請的執行緒進入阻塞,效能降低。

參考自Synchronized與Lock的區別與應用場景