6.2 JUC — 鎖 Locks

鎖是用於控制多線程訪問共享資源的工具。通常,鎖提供對共享資源的獨佔訪問:一次只有一個線程可以獲取鎖,對共享資源的所有訪問都需要首先獲取鎖。但是,一些鎖可以允許同時訪問共享資源,例如讀寫鎖ReadWriteLock。

鎖的分類

a.悲觀鎖與樂觀鎖

悲觀鎖:總是假設最壞的情況,每次去拿數據的時候都認爲別人會修改,所以每次在拿數據的時候都會上鎖,這樣別人想拿這個數據就會阻塞直到它拿到鎖(共享資源每次只給一個線程使用,其它線程阻塞,用完後再把資源轉讓給其它線程)。傳統的關係型數據庫裏邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖。Java中synchronized和ReentrantLock等獨佔鎖就是悲觀鎖思想的實現。

樂觀鎖:總是假設最好的情況,每次去拿數據的時候都認爲別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號機制和CAS算法實現。樂觀鎖適用於多讀的應用類型,這樣可以提高吞吐量,在Java中atomic包下面的原子變量類就是使用了樂觀鎖的一種實現方式CAS實現的。

b.公平鎖與非公平鎖

公平鎖:線程獲取鎖的時機是按照當前線程請求的絕對時間順序(當新線程嘗試獲取鎖的時候,除非同步隊列爲空,否則新線程必須進入同步隊列按序獲取鎖)。

非公平鎖:線程獲取鎖的時機是按照當前鎖的狀態來獲取(當新線程嘗試獲取鎖的時候,如果當前鎖被持有,則加入隊列,相當於公平鎖;如果當前鎖剛好被釋放,則直接獲得鎖,而不用進入同步隊列。相當於插隊)。

c.可重入鎖:當線程持有鎖後,如果它再次嘗試去獲取該鎖時它會立刻獲取到該鎖,而不會需要進入同步隊列等待。當然每次獲取鎖的操作都需要對應的釋放鎖操作。

按照不同的性質,大體有以下分類的鎖(彼此之間不是排斥關係,意思就是有些鎖既可以是悲觀鎖也可以是公平鎖,還可以是可重入的)。

Lock接口

在Lock接口出現之前,Java程序是靠synchronized關鍵字來實現鎖功能的,而Java SE 5之後,併發包(java.util.concurrent,JUC)中新增了Lock接口以及相關實現類,來實現鎖的功能。相比較之下,鎖的最大優勢就是可以自主控制,Lock 接口實現類提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作,Lock接口的實現類允許鎖在不同的作用範圍內獲取和釋放,並允許以任何順序獲取和釋放多個鎖。Lock接口提供了以下接口讓具體的實現類來完成:

  • void lock():獲取鎖,如果鎖不可用,則當前線程將出於線程調度目的而禁用,並處於休眠狀態,直到獲得鎖爲止。
  • void lockInterruptibly():可中斷的獲取鎖,和lock方法的不同之處在於該方法會響應中斷
  • boolean tryLock():嘗試非阻塞的獲取鎖,調用該方法後會立刻返回,如果獲取成功返回true,否則返回false
  • boolean tryLock():超時的獲取鎖,直到當前線程獲得鎖 | 被中斷 | 超時結束 返回
  • void unlock( ):釋放鎖
  • Condition newCondition():創建一個等待隊列,並與當前的鎖綁定。當前線程只有獲取了鎖,才能調用等待隊列的wait()方法,然後將此線程轉移至等待隊列,並釋放鎖。

ReadWriteLock接口

一個ReadWriteLock維護一個用於讀操作read Lock和一個用於寫操作的write Lock。沒有寫線程的情況下,多個讀線程可以同時持有讀lock,而寫lock是獨佔的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章