该样例根据Condition接口中文档注释样例改编
大致内容
- 创建一个有界容器,大小为10
- 有两个方法
- 一个用来存(put),没满的情况下
- 一个用来取(take),在有内容存在的情况下
代码
public class ConditionT {
public static void main(String[] args) {
BoundedContainer container = new BoundedContainer();
Runnable put = ()-> container.put("a");
Runnable take = container::take;
IntStream.range(0,10).forEach(i ->new Thread(put).start());//启动10个put线程
IntStream.range(0,10).forEach(i ->new Thread(take).start());//启动10个take线程
}
}
class BoundedContainer{
protected String[] elements = new String[10];//有界容器
protected final Lock lock = new ReentrantLock();//锁
protected final Condition notEmptyCondition = lock.newCondition();//容器有内容的条件下要进行的操作,等待队集
protected final Condition notFullCondition = lock.newCondition();//容器有内容且没满的条件下要进行的操作,另一个等待集
protected int elementCount;//容器strings[] ,非空元素的个数
protected int putIndex;//put操作的元素下标
protected int takeIndex;//take操作的元素下标
public void put(String element){
try {
lock.lock();
while (elementCount == elements.length){//如果容器满了就等待
notFullCondition.await();
}
if (putIndex<10){
elements[putIndex++] = element;
} else{
putIndex=0;//
}
elementCount++;
System.out.println("put method: "+ Arrays.toString(elements));
notEmptyCondition.signal();
}catch (InterruptedException e) {//中断异常
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void take(){
try {
lock.lock();
String token = null;//被取出的元素
while (elementCount == 0 ){//如果容器满了就等待
notEmptyCondition.await();
}
if (takeIndex<10){
token = elements[takeIndex];//被取出的元素
elements[takeIndex++] = null;//通过置null代表元素被取出
} else{
takeIndex=0;//到达容器上限置0
}
elementCount--;
System.out.println("take method: "+ Arrays.toString(elements)+" "+token+" is token");
notFullCondition.signal();
}catch (InterruptedException e) {//中断异常
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
结果
- 最后的结果是全
null,前提是put线程和take线程数目要一样。
如果put线程和take线程数目不一样会怎么样
put线程数大于take线程
IntStream.range(0,10).forEach(i ->new Thread(put).start());//10个put
IntStream.range(0,5).forEach(i ->new Thread(take).start());//5个take
结果正常
IntStream.range(0,16).forEach(i ->new Thread(put).start());//16个put
IntStream.range(0,5).forEach(i ->new Thread(take).start());//5个take
程序无法结束,因为有16个put,5个take,容器是10,16-5=11,导致1个put因为容器爆满而陷入await,且没有其他线程唤醒它,导致程序无法结束
take线程数大于put线程
IntStream.range(0,5).forEach(i ->new Thread(put).start());//5个put
IntStream.range(0,6).forEach(i ->new Thread(take).start());//6个take
程序无法结束,因为take有6个,put有5个,会导致有一个线程因为容器为空而陷入await,且没有线程可以唤醒它
小结
- 一个
Condition实例对应一个等待集 - 一个
Condition实例await和signal方法要成对出现 await方法会自动释放锁