關於互斥鎖: 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) { // 訪問或修改被鎖保護的共享狀態 }
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 LockLock 實現提供了比使用 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();// 注意這裏,能夠響應中斷