線程鎖,Lock,(ReentrantLock與synchronized)


關於互斥鎖: html

所謂互斥鎖, 指的是一次最多隻能有一個線程持有的鎖. 在jdk1.5以前, 咱們一般使用synchronized機制控制多個線程對共享資源的訪問. 而如今, Lock提供了比synchronized機制更普遍的鎖定操做, Lock和synchronized機制的主要區別: java

synchronized機制提供了對與每一個對象相關的隱式監視器鎖的訪問, 並強制全部鎖獲取和釋放均要出如今一個塊結構中, 當獲取了多個鎖時, 它們必須以相反的順序釋放. synchronized機制對鎖的釋放是隱式的, 只要線程運行的代碼超出了synchronized語句塊範圍, 鎖就會被釋放.  編程

但有時也須要以更爲靈活的方式使用鎖,好比說在併發編程中有時候,有時候容許以任何順序獲取和釋放多個鎖,從而支持使用Lock。
api

而Lock機制必須顯式的調用Lock對象的unlock()方法才能釋放鎖, 這爲獲取鎖和釋放鎖不出如今同一個塊結構中, 以及以更自由的順序釋放鎖提供了可能.  多線程

一:synchronized的兩種用法 併發

1.內部鎖 spa

Java 提供了原子性的內置鎖機制: sychronized 塊。它包含兩個部分:鎖對象的引用和這個鎖保護的代碼塊: .net


synchronized(lock) {
 // 訪問或修改被鎖保護的共享狀態
}



內部鎖扮演了互斥鎖( mutual exclusion lock, 也稱做 mutex )的角色,一個線程擁有鎖的時候,別的線程阻塞等待。

2.重進入 線程

指的是同一個線程屢次試圖獲取它所佔有的鎖,請求會成功。當釋放鎖的時候,直到重入次數清零,鎖才釋放完畢 code

Public class Widget {
      Public synchronized void doSomething(){
           …
      }
}
Public class LoggingWidget extends Widget {
   Public synchronized void doSomething(){
      System.out.println(toString()+」:calling doSomething」);
      Super.doSomething();
   }
}



通常來講,在多線程程序中,某個任務在持有某對象的鎖後才能運行任務,其餘任務只有在該任務釋放同一對象鎖後才能擁有對象鎖,而後執行任務。因而,想到,同一個任務在持有同一個對象的鎖後,在不釋放鎖的狀況下,繼續調用同一個對象的其餘同步(synchronized)方法,該任務是否會再次持有該對象鎖呢? 

    答案是確定的。

同一個任務在調用同一個對象上的其餘synchronized方法,能夠再次得到該對象鎖

synchronized  m1(){  
//加入此時對鎖a的計數是N  
 m2();  //進入m2的方法體以後鎖計數是N+1,離開m2後是N  
}  
synchronized m2(){}


二:ReentrantLock 實現了Lock

一個可重入的互斥鎖 Lock,它具備與使用 synchronized 方法和語句所訪問的隱式監視器鎖相同的一些基本行爲和語義,但功能更強大。

public interface Lock
Lock  實現提供了比使用  synchronized  方法和語句可得到的更普遍的鎖定操做。此實現容許更靈活的結構,能夠具備差異很大的屬性,能夠支持多個相關的  Condition  對象

ReentrantLock 將由最近成功得到鎖,而且尚未釋放該鎖的線程所擁有。當鎖沒有被另外一個線程所擁有時,調用 lock 的線程將成功獲取該鎖並返回。若是當前線程已經擁有該鎖,此方法將當即返回。可使用 isHeldByCurrentThread() 和 getHoldCount() 方法來檢查此狀況是否發生。

此類的構造方法接受一個可選的公平 參數。當設置爲 true 時,在多個線程的爭用下,這些鎖傾向於將訪問權授予等待時間最長的線程。不然此鎖將沒法保證任何特定訪問順序。與採用默認設置(使用不公平鎖)相比,使用公平鎖的程序在許多線程訪問時表現爲很低的整體吞吐量(即速度很慢,經常極其慢),可是在得到鎖和保證鎖分配的均衡性時差別較小。不過要注意的是,公平鎖不能保證線程調度的公平性。所以,使用公平鎖的衆多線程中的一員可能得到多倍的成功機會,這種狀況發生在其餘活動線程沒有被處理而且目前並未持有鎖時。還要注意的是,未定時的 tryLock 方法並無使用公平設置。由於即便其餘線程正在等待,只要該鎖是可用的,此方法就能夠得到成功。

建議老是 當即實踐,使用 lock 塊來調用 try,在以前/以後的構造中,最典型的代碼以下:
class X {
   private final ReentrantLock lock = new ReentrantLock();
   // ...

   public void m() { 
     lock.lock();  // block until condition holds
     try {
       // ... method body
     } finally {
       lock.unlock()
     }
   }
 }


ReentrantLock 的lock機制有2種,忽略中斷鎖和響應中斷鎖,這給咱們帶來了很大的靈活性。

好比:若是A、B 2個線程去競爭鎖,A線程獲得了鎖,B線程等待,可是A線程這個時候實在有太多事情要處理,就是 一直不返回,B線程可能就會等不及了,想中斷本身,再也不等待這個鎖了,轉而處理其餘事情。這個時候ReentrantLock就提供了2種機制,

第一,B線程中斷本身(或者別的線程中斷它),可是ReentrantLock 不去響應,繼續讓B線程等待,你再怎麼中斷,我全當耳邊風(synchronized原語就是如此);

第二,B線程中斷本身(或者別的線程中斷它),ReentrantLock 處理了這個中斷,而且再也不等待這個鎖的到來,徹底放棄。

代碼:  
lock.lockInterruptibly();// 注意這裏,能夠響應中斷
相關文章
相關標籤/搜索