Condition:
Condition是一個(gè)多線程間協(xié)調(diào)通信的工具類,使得某個(gè),或者某些線程一起等待某個(gè)條件(Condition),只有當(dāng)該條件具備( signal 或者 signalAll方法被帶調(diào)用)時(shí) ,這些等待線程才會被喚醒,從而重新爭奪鎖。
ReentrantLock:
(重入鎖)是jdk的concurrent包提供的一種獨(dú)占鎖的實(shí)現(xiàn)。它繼承自Dong Lea的 AbstractQueuedSynchronizer(同步器),確切的說是ReentrantLock的一個(gè)內(nèi)部類繼承了AbstractQueuedSynchronizer,ReentrantLock只不過是代理了該類的一些方法,可能有人會問為什么要使用內(nèi)部類在包裝一層? 我想是安全的關(guān)系,因?yàn)锳bstractQueuedSynchronizer中有很多方法,還實(shí)現(xiàn)了共享鎖,Condition(稍候再細(xì)說)等功能,如果直接使ReentrantLock繼承它,則很容易出現(xiàn)AbstractQueuedSynchronizer中的API被無用的情況。
對比wati,notify,notifyAll
java 1.5 出現(xiàn)的顯式協(xié)作Condition接口的 await、signal、signalAll 也可以說是普通并發(fā)協(xié)作 wait、notify、notifyAll 的升級;普通并發(fā)協(xié)作 wait、notify、notifyAll 需要與synchronized配合使用,顯式協(xié)作Condition 的 await、signal、signalAll 需要與顯式鎖Lock配合使用(Lock.newCondition()),調(diào)用await、signal、signalAll方法都必須在lock 保護(hù)之內(nèi)。
和wait一樣,await在進(jìn)入等待隊(duì)列后會釋放鎖和cpu,當(dāng)被其他線程喚醒或者超時(shí)或中斷后都需要重新獲取鎖,獲取鎖后才會從await方法中退出,await同樣和wait一樣存在等待返回不代表?xiàng)l件成立的問題,所以也需要主動循環(huán)條件判斷;await提供了比wait更加強(qiáng)大的機(jī)制,譬如提供了可中斷或者不可中斷的await機(jī)制等;特別注意Condition也有wait、notify、notifyAll方法,因?yàn)槠湟彩荗bject,所以在使用顯式協(xié)作機(jī)制時(shí)千萬不要和synchronized 情況下的協(xié)作機(jī)制混合使用,避免出現(xiàn)詭異問題。
用一個(gè)stackoverflow的一個(gè)實(shí)現(xiàn)BlockingQueue例子讓大家印象深刻一點(diǎn):
用wait,notify,notifyAll實(shí)現(xiàn):
public class BlockingQueue<T> {
private Queue<T> mQueue = new LinkedList<>();
private int mCapacity;
public BlockingQueue(int capacity) {
this.mCapacity = capacity;
}
public synchronized void put(T element) throws InterruptedException{
while (mQueue.size() == mCapacity){
wait();
}
mQueue.add(element);
notify();
}
public synchronized T take() throws InterruptedException{
while (mQueue.isEmpty()){
wait();
}
T item = mQueue.remove();
notify();
return item;
}
}
用await,signal,signalAll實(shí)現(xiàn):
public class BlockingQueue<T> {
private Queue<T> mQueue = new LinkedList<>();
private int mCapacity;
private Lock mLock = new ReentrantLock();
private Condition mNotFull = mLock.newCondition();
private Condition mNotEmpty = mLock.newCondition();
public BlockingQueue(int capacity) {
this.mCapacity = capacity;
}
public synchronized void put(T element) throws InterruptedException{
mLock.lockInterruptibly();
try {
while (mQueue.size() == mCapacity){
mNotFull.await();
}
mQueue.add(element);
mNotEmpty.signal();
}finally {
mLock.unlock();
}
}
public synchronized T take() throws InterruptedException{
mLock.lockInterruptibly();
try {
while (mQueue.size() == 0){
mNotEmpty.await();
}
T item = mQueue.remove();
mNotFull.signal();
return item;
}finally {
mLock.unlock();
}
}
}