为什么消费者会出现索引越界呢?
因为缓冲区消费判定时候使用了if判断,wait() 被叫醒后,如果其他线程已经抢到了对象锁并且已经消费了一个产品后,那么产品就为0了,现在直接进行取产品就会发生索引越界,所以此时应该使用while循环 使其一直判定 是否为0 是0就等待 继续抢 往复循环
缓冲区:
public class OrderPool {
private CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
//生产者放入订单
public synchronized void produceOrder() {
while (list.size() == 30) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add("order");
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "---->生产一个订单,还有" + list.size() + "个订单");
try {
TimeUnit.MILLISECONDS.sleep(300L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 为什么下面判断条件用if的时候会报索引越界呢?
* 因为该线程醒了之后要再次判断是否为0
* 因为不知道等待的时候其他线程是否更新了 list.size()
* 若此时其他消费者已经消费了商品 但是自己又没有判断lise.size() 是否为0 此时取出第一个订单 就会出现索引越界
* 所以此时应该使用while一直判断是否为0 如果为0 继续等待
*/
public synchronized void consumerOrder() {
while (list.size() == 0) {
System.out.println("订单池没有订单,消费者等待中");
try {//只能用在同步方法 或者同步代码块中
/*调用wait()方法后 立刻释放对象锁 线程进入当前对象的等待池
* 被唤醒之后,要拿到对象锁后才可以继续执行
* 若没有拿到对象锁 则会一直等待*/
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//若订单池中有订单 就消耗一个订单
list.remove(0);
// this.notify(); 也是只能出现在同步代码块中 notify() 随机唤醒一个线程
this.notifyAll();
System.out.println(Thread.currentThread().getName() + "---->消费一个订单,还有" + list.size() + "个");
try {
TimeUnit.MILLISECONDS.sleep(200L);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消费者:
public class Consumer implements Runnable {
private OrderPool orderPool;
public Consumer() {
}
public Consumer(OrderPool orderPool) {
this.orderPool = orderPool;
}
@Override
public void run() {
while (true) {
orderPool.consumerOrder();
}
}
}
生产者:
public class Produce implements Runnable {
private OrderPool orderPool;
public Produce() {
}
public Produce(OrderPool orderPool) {
this.orderPool = orderPool;
}
@Override
public void run() {
while (true) {
orderPool.produceOrder();
}
}
}