ReentrantLock是一種可重入的互斥鎖,而且加鎖是一種顯式操做,對邏輯控制的靈活性遠遠大於synchronized關鍵字。重入鎖是能夠徹底替代synchronized。而且重入鎖的性能是遠高於synchronized的,可是jdk6.0開始,jdk對synchronized作了大量的優化,使得二者性能差距不大。另外,ReentrantLock可結合Condition、以及提供了中斷響應、鎖申請等待限時、公平鎖等。java
ReentrantLock分爲「公平鎖」和「非公平鎖」。它們的區別體如今獲取鎖的機制上是否公平。在「公平鎖」的機制下,線程依次排隊獲取鎖;而「非公平鎖」在鎖是可獲取狀態時,無論本身是否是在隊列的開頭都會獲取鎖。函數
運行以下代碼,對比公平鎖和非公平鎖的運行結果性能
public static void main(String[] args) throws InterruptedException { Lock noFairReentrantLock = new ReentrantLock(); Lock fairReentrantLock = new ReentrantLock(true); Thread[] threads = new Thread[10]; for(int i=0;i<10;i++){ threads[i] = new Thread(()->{ System.out.println(Thread.currentThread().getName()+" [start]"); fairReentrantLock.lock();//也能夠切換爲非公平鎖,觀察運行結果 try { System.out.println(Thread.currentThread().getName()+" [得到鎖]"); }finally { fairReentrantLock.unlock(); } }); } for(int i=0;i<5;i++){ threads[i].start(); } for(int i=0;i<5;i++){ threads[i].join(); } } }
對於synchronized塊來講,要麼獲取到鎖執行,要麼持續等待。而重入鎖的中斷響應功能就合理地避免了這樣的狀況。好比,一個正在等待獲取鎖的線程被「告知」無須繼續等待下去,就能夠中止工做了。優化
下面咱們看一個利用中斷響應功能解決的一個死鎖問題線程
public static void main(String[] args) throws InterruptedException { ReentrantLock lock1 = new ReentrantLock(); ReentrantLock lock2 = new ReentrantLock(); //線程t1和t2構成了死鎖,此時咱們能夠中斷的方式解決死鎖問題 Runnable runnable = ()->{ try { if(Thread.currentThread().getName().equals("t1")){ lock1.lockInterruptibly(); //在加鎖的過程當中仍然能夠相應中斷 Thread.sleep(100); lock2.lockInterruptibly(); }else{ lock2.lockInterruptibly(); Thread.sleep(100); lock1.lockInterruptibly(); } } catch (InterruptedException e) { e.printStackTrace(); }finally { if (lock1.isHeldByCurrentThread()) lock1.unlock(); if (lock2.isHeldByCurrentThread()) lock2.unlock(); } }; Thread t1 = new Thread(runnable,"t1"); Thread t2 = new Thread(runnable,"t2"); t1.start();t2.start(); Thread.sleep(1000); //以中斷的方式解決死鎖問題 t2.interrupt(); }
可使用 tryLock()或者tryLock(long timeout, TimeUtil unit) 方法進行一次限時的鎖等待。code
public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(); Runnable runnable = ()->{ try { if (lock.tryLock(1, TimeUnit.SECONDS)) { // 等待1秒 Thread.sleep(2000); } else { System.err.println(Thread.currentThread().getName() + "獲取鎖失敗!"); } } catch (Exception e) { if (lock.isHeldByCurrentThread()) lock.unlock(); } }; Thread t1 = new Thread(runnable,"t1"); Thread t2 = new Thread(runnable,"t2"); t1.start();t2.start(); }
配合關鍵字synchronized使用的方法如:await()、notify()、notifyAll(),一樣配合ReentrantLock 使用的Conditon提供瞭如下方法:對象
public interface Condition { void await() throws InterruptedException; // 相似於Object.wait() void awaitUninterruptibly(); // 與await()相同,但不會再等待過程當中響應中斷 long awaitNanos(long nanosTimeout) throws InterruptedException; boolean await(long time, TimeUnit unit) throws InterruptedException; boolean awaitUntil(Date deadline) throws InterruptedException; void signal(); // 相似於Obejct.notify() void signalAll(); }
ReentrantLock 配合 Condition的例子隊列
public static void main(String[] args) throws InterruptedException { ReentrantLock lock = new ReentrantLock(true); Condition condition = lock.newCondition(); Thread t = new Thread(()->{ try { lock.lock(); System.err.println(Thread.currentThread().getName() + "-線程開始等待..."); condition.await(); System.err.println(Thread.currentThread().getName() + "-線程繼續進行了"); } catch (InterruptedException e) { e.printStackTrace(); } finally { lock.unlock(); } }, "t1"); t.start(); Thread.sleep(1000); System.err.println("過了1秒後..."); lock.lock(); condition.signal(); // 調用該方法前須要獲取到建立該對象的鎖不然會產生java.lang.IllegalMonitorStateException異常 lock.unlock(); }
// 建立一個 ReentrantLock ,默認是「非公平鎖」。 ReentrantLock() // 建立策略是fair的 ReentrantLock。fair爲true表示是公平鎖,fair爲false表示是非公平鎖。 ReentrantLock(boolean fair) // 查詢當前線程保持此鎖的次數。 int getHoldCount() // 返回目前擁有此鎖的線程,若是此鎖不被任何線程擁有,則返回 null。 protected Thread getOwner() // 返回一個 collection,它包含可能正等待獲取此鎖的線程。 protected Collection<Thread> getQueuedThreads() // 返回正等待獲取此鎖的線程估計數。 int getQueueLength() // 返回一個 collection,它包含可能正在等待與此鎖相關給定條件的那些線程。 protected Collection<Thread> getWaitingThreads(Condition condition) // 返回等待與此鎖相關的給定條件的線程估計數。 int getWaitQueueLength(Condition condition) // 查詢給定線程是否正在等待獲取此鎖。 boolean hasQueuedThread(Thread thread) // 查詢是否有些線程正在等待獲取此鎖。 boolean hasQueuedThreads() // 查詢是否有些線程正在等待與此鎖有關的給定條件。 boolean hasWaiters(Condition condition) // 若是是「公平鎖」返回true,不然返回false。 boolean isFair() // 查詢當前線程是否保持此鎖。 boolean isHeldByCurrentThread() // 查詢此鎖是否由任意線程保持。 boolean isLocked() // 獲取鎖。 void lock() // 若是當前線程未被中斷,則獲取鎖。 void lockInterruptibly() // 返回用來與此 Lock 實例一塊兒使用的 Condition 實例。 Condition newCondition() // 僅在調用時鎖未被另外一個線程保持的狀況下,才獲取該鎖。 boolean tryLock() // 若是鎖在給定等待時間內沒有被另外一個線程保持,且當前線程未被中斷,則獲取該鎖。 boolean tryLock(long timeout, TimeUnit unit) // 試圖釋放此鎖。 void unlock()