可重入鎖和不可重入鎖

鎖的簡單應用html


用lock來保證原子性(this.count++這段代碼稱爲臨界區)java

什麼是原子性,就是不可分,從頭執行到尾,不能被其餘線程同時執行。數組

可經過CAS來實現原子操做this

CAS(Compare and Swap):spa

CAS操做須要輸入兩個數值,一箇舊值(指望操做前的值)和一個新值,在操做期間先比較下舊值有沒有發生變化,若是沒有發生變化,才交換成新值,發生了變化則不交換。操作系統

CAS主要經過compareAndSwapXXX()方法來實現,而這個方法的實現須要涉及底層的unsafe類.net

unsafe類:java不能直接訪問操做系統底層,而是經過本地方法來訪問。Unsafe類提供了硬件級別的原子操做線程

這裏有個介紹原子操做的博客設計

https://my.oschina.net/xinxingegeya/blog/499223code

還有對unsafe類詳解的博客

http://www.cnblogs.com/mickole/articles/3757278.html

 

 1 public class Counter{
 2     private Lock lock = new Lock();
 3     private int count = 0;
 4     public int inc(){
 5         lock.lock();
 6         this.count++;
 7         lock.unlock();
 8         return count;
 9     }
10 }

不可重入鎖


先來設計一種鎖

 1 public class Lock{
 2     private boolean isLocked = false;
 3     public synchronized void lock() throws InterruptedException{
 4         while(isLocked){    
 5             wait();
 6         }
 7         isLocked = true;
 8     }
 9     public synchronized void unlock(){
10         isLocked = false;
11         notify();
12     }
13 }

這實際上是個不可重入鎖,舉個例子

 1 public class Count{
 2     Lock lock = new Lock();
 3     public void print(){
 4         lock.lock();
 5         doAdd();
 6         lock.unlock();
 7     }
 8     public void doAdd(){
 9         lock.lock();
10         //do something
11         lock.unlock();
12     }
13 }

當調用print()方法時,得到了鎖,這時就沒法再調用doAdd()方法,這時必須先釋放鎖才能調用,因此稱這種鎖爲不可重入鎖,也叫自旋鎖。

可重入鎖


設計以下:

 1 public class Lock{
 2     boolean isLocked = false;
 3     Thread  lockedBy = null;
 4     int lockedCount = 0;
 5     public synchronized void lock()
 6             throws InterruptedException{
 7         Thread thread = Thread.currentThread();
 8         while(isLocked && lockedBy != thread){
 9             wait();
10         }
11         isLocked = true;
12         lockedCount++;
13         lockedBy = thread;
14     }
15     public synchronized void unlock(){
16         if(Thread.currentThread() == this.lockedBy){
17             lockedCount--;
18             if(lockedCount == 0){
19                 isLocked = false;
20                 notify();
21             }
22         }
23     }
24 }

相對來講,可重入就意味着:線程能夠進入任何一個它已經擁有的鎖所同步着的代碼塊。

第一個線程執行print()方法,獲得了鎖,使lockedBy等於當前線程,也就是說,執行的這個方法的線程得到了這個鎖,執行add()方法時,一樣要先得到鎖,因不知足while循環的條件,也就是不等待,繼續進行,將此時的lockedCount變量,也就是當前得到鎖的數量加一,當釋放了全部的鎖,才執行notify()。若是在執行這個方法時,有第二個線程想要執行這個方法,由於lockedBy不等於第二個線程,致使這個線程進入了循環,也就是等待,不斷執行wait()方法。只有當第一個線程釋放了全部的鎖,執行了notify()方法,第二個線程才得以跳出循環,繼續執行。

這就是可重入鎖的特色。

java中經常使用的可重入鎖

synchronized

java.util.concurrent.locks.ReentrantLock

ps:順便記錄下java中實現原子操做的類(記錄至http://blog.csdn.net/huzhigenlaohu/article/details/51646455

  • AtomicIntegerFieldUpdater:原子更新整型的字段的更新器
  • AtomicLongFieldUpdater:原子更新長整型字段的更新器
  • AtomicStampedReference:原子更新帶有版本號的引用類型。該類將整型數值與引用關聯起來,可用於原子的更新數據和數據的版本號,能夠解決使用CAS進行原子更新時可能出現的ABA問題。
  • AtomicReference :原子更新引用類型
  • AtomicReferenceFieldUpdater :原子更新引用類型裏的字段
  • AtomicMarkableReference:原子更新帶有標記位的引用類型。能夠原子更新一個布爾類型的標記位和應用類型
  • AtomicIntegerArray :原子更新整型數組裏的元素
  • AtomicLongArray :原子更新長整型數組裏的元素
  • AtomicReferenceArray : 原子更新引用類型數組的元素
  • AtomicBooleanArray :原子更新布爾類型數組的元素
  • AtomicBoolean :原子更新布爾類型
  • AtomicInteger: 原子更新整型
  • AtomicLong: 原子更新長整型
相關文章
相關標籤/搜索