當咱們瞭解了多線程生成的緣由以後,會有相應的解決辦法,最典型的就是 synchronized 和 lock。lock能夠說是 synchronized 的一個替代品,synchronized 能作的事,lock 基本均可以作,並且能作得更好。他們的一些區別是:java
這樣能夠看到,lock 比起 synchronized 具備更細粒度的控制。可是也不是說 lock 就徹底能夠取代 synchronized,由於 lock 的學習成本,複雜度等方面要比 synchronized 高,對於初級 java 程序員,使用 synchronized 的風險要比 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() 能夠用於對一段代碼進行加鎖,這樣別的代碼在鎖釋放以前須要進行等待,須要注意,lock不會像 synchronized 那樣自動釋放鎖,因此:必定要放在 try-finally塊中,保證鎖的釋放。 例如:併發
try { lock.lock(); ...... } finally { lock.unlock(); }
這裏首先須要瞭解兩個概念才能更好的理解這個方法:函數
對於線程的打擾機制,每一個線程都有一個打擾標誌。源碼分析
因此說,對於 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的等待過程。
用於獲取一個 Conodition 對象。Condition 對象是比 Lock 更細粒度的控制。要很好的理解 condition,我的以爲必需要知道,生產者消費者問題。
簡單來講就是,咱們都瞭解生產者在緩衝區滿了的時候須要休眠,此時會再喚起一個線程,那麼你此時喚醒的是生成者仍是消費者呢,若是是消費者,很好;可是若是是喚醒生產者,那還要再休眠,此時就浪費資源了。condition就能夠用來解決這個問題,能保證每次喚醒的都是消費者。具體參考:Java 多線程:condition關鍵字
lock 方法大致就介紹到這裏。
可重入鎖:指同一個線程,外層函數得到鎖以後,內層遞歸函數仍有得到該鎖的代碼,可是不受影響。
**可重入鎖的最大做用就是 能夠避免死鎖。**例如:A線程有兩個方法 a 和 b,其中 a 方法會調用 b 方法,假如 a,b 兩個方法都須要得到鎖,那麼首先 a 方法先執行,會得到鎖,此時 b方法將永遠得到不了鎖,b 方法將一直阻塞住, a 方法因爲 b 方法沒有執行完,它自己也 不釋放鎖,此時就會形成一個死鎖。 ReentrantLock 就是一個可重入鎖。真正使用鎖的時候,通常是 Lock lock = new ReentrantLock();而後 使用 Lock 接口方法。
接口代碼以下:
public interface ReadWriteLock { Lock readLock(); Lock writeLock(); }
ReadWriteLock 能夠算是 Lock 的一個細分,合理使用有利於提升效率。好比說, 對於一個變量 i, A,B 線程同時讀,那麼不會形成錯誤的結果,因此此時是容許併發,可是若是是同時寫操做,那麼則是有可能形成錯誤。因此真正使用的時候,可使用細分須要的是讀鎖仍是寫鎖,再相應地進行加鎖。
Ps:從代碼也能夠看出,ReadWriteLock 和 Lock 沒有關係,既不繼承,也不是實現。