来源
condition的API和Object的wait、notify用法大致相同,但是Object需要配合synchronized来使用,如果使用显示锁Lock无法使用。因此Condition应运而生,他是由Lock的API创建出来的等待/通知机制
API
await()、signal()和wait()、notify()相同,但是使用前需要加锁,Lock.lock
与Object区别
Lock.newCondition()可以获取多个Condition,也就是说,在一个lock对象上,可以有多个等待队列,而Object的等待通知在一个Object上,只能有一个等待队列。
Condition模拟阻塞队列
public class BoundedQueue1<T> {
public List<T> q; //这个列表用来存队列的元素
private int maxSize; //队列的最大长度
private Lock lock = new ReentrantLock();
private Condition addConditoin = lock.newCondition();
private Condition removeConditoin = lock.newCondition();
public BoundedQueue1(int size) {
q = new ArrayList<>(size);
maxSize = size;
}
public void add(T e) {
lock.lock();
try {
while (q.size() == maxSize) {
addConditoin.await();
}
q.add(e);
removeConditoin.signal(); //执行了添加操作后唤醒因队列空被阻塞的删除操作
} catch (InterruptedException e1) {
Thread.currentThread().interrupt();
} finally {
lock.unlock();
}
}
public T remove() {
lock.lock();
try {
while (q.size() == 0) {
removeConditoin.await();
}
T e = q.remove(0);
addConditoin.signal(); //执行删除操作后唤醒因队列满而被阻塞的添加操作
return e;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return null;
} finally {
lock.unlock();
}
}
}
Object的wait/notify模拟阻塞队列
public class MyBlockQueue {
private Object[] objs; // 数据数组
private volatile int count; // 当前数组中对象个数
private volatile int putIndex; // 数组中存储对象的索引
private volatile int takeIndex; // 数组中取对象的索引
private Object full;
private Object empty;
public MyBlockQueue(int size) {
super();
count = 0;
putIndex = 0;
takeIndex = 0;
objs = new Object[size];
full = new Object();
empty = new Object();
}
private void add(Object obj) {
synchronized (full) {
while (objs.length == count) {
try {
full.wait();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
System.out.println("list add:" + obj);
objs[putIndex] = obj; // 根据索引依次存
if (++putIndex == objs.length) { // 当数组存满,从0开始存,从1开始取
putIndex = 0;
}
}
synchronized (empty) {
++count;
empty.notify();
}
}
private Object get() {
Object obj;
synchronized (empty) {
try {
while (count == 0) {
empty.wait();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
obj = objs[takeIndex];
if(takeIndex + 1 == objs.length) {
takeIndex = 0;
}else {
takeIndex++;
}
}
synchronized (full) {
count--;
full.notify();
System.out.println(Thread.currentThread().getName() + ":" + obj);
return obj;
}
}
public static void main(String[] args) throws InterruptedException {
MyBlockQueue m = new MyBlockQueue(5);
for (int i = 0; i < 2; i++) {
new Thread(new Runnable() {
@Override
public void run() {
m.get();
}
}).start();
}
for (int i = 0; i < 10; i++) {
new Thread(new Runnable() {
@Override
public void run() {
Object obj = new Object();
m.add(obj);
}
}).start();
}
}
}