Lock && Condition_实现有界缓存
Lock是一种广义的内置锁,Condition也是一种广义的内置条件队列。
内置条件队列存在一些缺陷。每个内置锁都只能有一个相关的条件队列,因而多个线程可能在同一个条件队列上等待不同的条件谓词,并且在最常见的加锁模式下公开条件队列对象。
这些因素都使得无法满足在使用notifyAll时所有等待线程为同一类型的需求。如果想编写一个带有多个条件谓词的并发对象,或者想获得除了条件队列可见性的更多控制权,就可以使用显示的Lock和Condition而不是内置锁和内置条件队列,这是一种更灵活的选择。
Lock比内置锁提供了更为丰富的功能,Condition同样比内置条件队列提供了更丰富的功能:在每个锁上可能存在多个等待、条件等待可以是可中断的、基于时限的等待,以及公平的或非公平的队列操作。
与内置条件队列不同的是,对于每个Lock,可以有任意数量的Condition对象。Condition对象继承了相关的Lock对象的公平性,对于公平的锁,线程会依照FIFO顺序从Condition.await中释放。
下面这段程序给出了有界缓存的另一种实现,即使用两个Condition,分别为notFull和notEmpty,用于表示”非满“和”非空“两个条件谓词。当缓存为空时,take将阻塞并等待notEmpty,此时put向notEmpty发送信号,可以解除任何在take中阻塞的线程。
使用显示条件变量的有界缓存
package sync;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created with IntelliJ IDEA.
* User: ASUS
* Date: 14-9-1
* Time: 下午9:20
* To change this template use File | Settings | File Templates.
*/
public class ConditionBoundedBuffer<T> {
protected final Lock lock = new ReentrantLock();
//条件谓词:notFull
private final Condition notFull = lock.newCondition();
//条件谓词:notEmpty
private final Condition notEmpty = lock.newCondition();
private final T[] items;
private int tail, head, count;
protected ConditionBoundedBuffer(int size) {
items = (T[]) new Object[size];
}
/**
* 阻塞并直到notFull
*
* @param x
* @throws InterruptedException
*/
public void put(T x) throws InterruptedException {
lock.lock();
try {
while (count == items.length) {
// 阻塞,等待非满条件
System.out.println("not full await");
notFull.await();
}
items[tail] = x;
if (++tail == items.length) {
tail = 0;
}
++count;
notEmpty.signal();
} finally {
lock.unlock();
}
}
/**
* 阻塞并直到notEmpty
*
* @return
* @throws InterruptedException
*/
public T take() throws InterruptedException {
lock.lock();
try {
while (count == 0) {
// 阻塞,等待非空条件
System.out.println("not empty await");
notEmpty.await(); //现在有界缓存为空,要等到非空状态才能取出元素
}
T x = items[head];
items[head] = null;
if (++head == items.length) {
head = 0;
}
--count;
notFull.signal(); //元素已被取出,通知非满状态
return x;
} finally {
lock.unlock();
}
}
public static void main(String args[]) {
final ConditionBoundedBuffer buffer = new ConditionBoundedBuffer(10);
//线程t2打印缓存中的消息
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
while (true) {
try {
System.out.println(buffer.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
//线程t1放入缓存消息
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 100; i++) {
try {
buffer.put(new String("sadsasd"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
t2.start();
t1.start();
}
}
============END============
来源:oschina
链接:https://my.oschina.net/u/1469576/blog/309323