Condition:
Condition是一个多线程间协调通信的工具类,使得某个,或者某些线程一起等待某个条件(Condition),只有当该条件具备( signal 或者 signalAll方法被带调用)时 ,这些等待线程才会被唤醒,从而重新争夺锁。
ReentrantLock:
(重入锁)是jdk的concurrent包提供的一种独占锁的实现。它继承自Dong Lea的 AbstractQueuedSynchronizer(同步器),确切的说是ReentrantLock的一个内部类继承了AbstractQueuedSynchronizer,ReentrantLock只不过是代理了该类的一些方法,可能有人会问为什么要使用内部类在包装一层? 我想是安全的关系,因为AbstractQueuedSynchronizer中有很多方法,还实现了共享锁,Condition(稍候再细说)等功能,如果直接使ReentrantLock继承它,则很容易出现AbstractQueuedSynchronizer中的API被无用的情况。
对比wati,notify,notifyAll
java 1.5 出现的显式协作Condition接口的 await、signal、signalAll 也可以说是普通并发协作 wait、notify、notifyAll 的升级;普通并发协作 wait、notify、notifyAll 需要与synchronized配合使用,显式协作Condition 的 await、signal、signalAll 需要与显式锁Lock配合使用(Lock.newCondition()),调用await、signal、signalAll方法都必须在lock 保护之内。
和wait一样,await在进入等待队列后会释放锁和cpu,当被其他线程唤醒或者超时或中断后都需要重新获取锁,获取锁后才会从await方法中退出,await同样和wait一样存在等待返回不代表条件成立的问题,所以也需要主动循环条件判断;await提供了比wait更加强大的机制,譬如提供了可中断或者不可中断的await机制等;特别注意Condition也有wait、notify、notifyAll方法,因为其也是Object,所以在使用显式协作机制时千万不要和synchronized 情况下的协作机制混合使用,避免出现诡异问题。
用一个stackoverflow的一个实现BlockingQueue例子让大家印象深刻一点:
用wait,notify,notifyAll实现:
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实现:
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);
mNotFull.signal();
}finally {
mLock.unlock();
}
}
public synchronized T take() throws InterruptedException{
mLock.lockInterruptibly();
try {
while (mQueue.size() == 0){
mNotEmpty.await();
}
T item = mQueue.remove();
mNotEmpty.signal();
return item;
}finally {
mLock.unlock();
}
}
}
网友评论