Java 多線程:Lock接口(接口方法分析,ReentrantLock,ReadWriteLock

前言


當咱們瞭解了多線程生成的緣由以後,會有相應的解決辦法,最典型的就是 synchronized 和 lock。lock能夠說是 synchronized 的一個替代品,synchronized 能作的事,lock 基本均可以作,並且能作得更好。他們的一些區別是:java

  • lock在獲取鎖的過程能夠被中斷。
  • lock能夠嘗試獲取鎖,若是鎖被其餘線程持有,則返回 false,不會使當前線程休眠。
  • lock在嘗試獲取鎖的時候,傳入一個時間參數,若是在這個時間範圍內,沒有得到鎖,那麼就是終止請求。
  • synchronized 會自動釋放鎖,lock 則不會自動釋放鎖。

這樣能夠看到,lock 比起 synchronized 具備更細粒度的控制。可是也不是說 lock 就徹底能夠取代 synchronized,由於 lock 的學習成本,複雜度等方面要比 synchronized 高,對於初級 java 程序員,使用 synchronized 的風險要比 lock 低。程序員

目錄


  • Lock 接口方法分析
  • RentrantLock
  • ReadWriteLock

Java Lock接口源碼分析


Lock 接口方法以下:多線程

public interface Lock {
    void lock();
    void lockInterruptibly() throws InterruptedException;
    boolean tryLock();
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock();
    Condition newCondition();
}

lock,unlock 方法

lock() 能夠用於對一段代碼進行加鎖,這樣別的代碼在鎖釋放以前須要進行等待,須要注意,lock不會像 synchronized 那樣自動釋放鎖,因此:必定要放在 try-finally塊中,保證鎖的釋放。 例如:併發

try {
    lock.lock();
    ......
} finally {
    lock.unlock();  
}

tryLock 方法

  • tryLock():嘗試得到鎖,若是成功,返回 true,不然,返回 false。
  • tryLock(long time,TimeUnit unit):在必定的時間內嘗試得到鎖,而且在這段時間直接能夠被打斷。若是成功得到,那麼將返回 true,不然,返回 false。

lockInterruptibly 方法

這裏首先須要瞭解兩個概念才能更好的理解這個方法:函數

  • 線程的打擾機制
  • Thread類的interrupt,interrupted,isInterrupted方法的區別

對於線程的打擾機制,每一個線程都有一個打擾標誌。源碼分析

  • 若是線程在sleep或wait,join,此時若是別的進程調用此進程的 interrupt()方法,此線程會被喚醒並被要求處理InterruptedException;
  • 若是線程在運行,則不會收到提醒。可是此線程的 「打擾標誌」會被設置。

因此說,對於 interrupt() 方法:不會中斷一個正在運行的線程。學習

對於 interrupt,interrupted,isInterrupted方法的區別:this

interrupt 方法上面有說到了。對於 interrupted 和 isInterrupted 方法,stackoverflow 說得很好了:線程

interrupted() is static and checks the current thread. isInterrupted() is an instance method which checks the Thread object that it is called on.code

A common error is to call a static method on an instance.

Thread myThread = ...; if (myThread.interrupted()) {} // WRONG! This might not be checking myThread. if (myThread.isInterrupted()) {} // Right!

Another difference is that interrupted() also clears the status of the current thread. In other words, if you call it twice in a row and the thread is not interrupted between the two calls, the second call will return false even if the first call returned true.

The Javadocs tell you important things like this; use them often!

下面再介紹下 lockInterruptibly 方法:

當經過這個方法去獲取鎖時,若是線程正在等待獲取鎖,則這個線程可以響應中斷,即中斷線程的等待狀 態。例如當兩個線程同時經過lock.lockInterruptibly()想獲取某個鎖時,倘若此時線程A獲取到了鎖,而線程B只有在等待,那麼對線程B調用threadB.interrupt()方法可以中斷線程B的等待過程。

newCondition()

用於獲取一個 Conodition 對象。Condition 對象是比 Lock 更細粒度的控制。要很好的理解 condition,我的以爲必需要知道,生產者消費者問題。

簡單來講就是,咱們都瞭解生產者在緩衝區滿了的時候須要休眠,此時會再喚起一個線程,那麼你此時喚醒的是生成者仍是消費者呢,若是是消費者,很好;可是若是是喚醒生產者,那還要再休眠,此時就浪費資源了。condition就能夠用來解決這個問題,能保證每次喚醒的都是消費者。具體參考:Java 多線程:condition關鍵字

lock 方法大致就介紹到這裏。

ReentrantLock


可重入鎖:指同一個線程,外層函數得到鎖以後,內層遞歸函數仍有得到該鎖的代碼,可是不受影響。

**可重入鎖的最大做用就是 能夠避免死鎖。**例如:A線程有兩個方法 a 和 b,其中 a 方法會調用 b 方法,假如 a,b 兩個方法都須要得到鎖,那麼首先 a 方法先執行,會得到鎖,此時 b方法將永遠得到不了鎖,b 方法將一直阻塞住, a 方法因爲 b 方法沒有執行完,它自己也 不釋放鎖,此時就會形成一個死鎖。 ReentrantLock 就是一個可重入鎖。真正使用鎖的時候,通常是 Lock lock = new ReentrantLock();而後 使用 Lock 接口方法。

ReadWriteLock


接口代碼以下:

public interface ReadWriteLock {  
    Lock readLock();  
    Lock writeLock();  
}

ReadWriteLock 能夠算是 Lock 的一個細分,合理使用有利於提升效率。好比說, 對於一個變量 i, A,B 線程同時讀,那麼不會形成錯誤的結果,因此此時是容許併發,可是若是是同時寫操做,那麼則是有可能形成錯誤。因此真正使用的時候,可使用細分須要的是讀鎖仍是寫鎖,再相應地進行加鎖。

Ps:從代碼也能夠看出,ReadWriteLock 和 Lock 沒有關係,既不繼承,也不是實現。

相關文章
相關標籤/搜索