阻塞式队列
生产者消费者模型
- 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
相信各位同学在操作系统中了解过该模型需要用到俩个方法wait()和notify();(一个是等待,另外一个是唤醒)
1.需要用到Object.wait()方法(等待)
- wait()方法就是使线程停止运行。
- 方法wait()的作用是使当前执行代码的线程进行等待,wait()方法是Object类的方法,该方法是用来将当前线程置入“预执行队列”中,并且在wait()所在的代码处停止执行,直到接到通知或被中断为止。
- wait()方法只能在同步方法中或同步块中调用。如果调用wait()时,没有持有适当的锁,会抛出异常。
- wait()方法执行后,当前线程释放锁,线程与其它线程竞争重新获取锁。
public class MyWait {
public static void main(String[] args) throws InterruptedException {
Object object = new Object();
synchronized (object){
System.out.println("等待中..");
object.wait();
System.out.println("等待已过...");
}
System.out.println("main方法结束...");
}
}
这样在执行到object.wait()之后就一直等待下去,那么程序肯定不能一直这么等待下去了。这个时候就需要使用到了另外一个方法唤醒的方法notify()。
2.需要用到Object.notify()方法(唤醒)
- notify方法就是使停止的线程继续运行。
- 方法notify()也要在同步方法或同步块中调用,该方法是用来通知那些可能等待该对象的对象锁的其它线程,对其发出通知notify,并使它们重新获取该对象的对象锁。如果有多个线程等待,则有线程规划器随机挑选出一个呈wait状态的线程。
- 在notify()方法后,当前线程不会马上释放该对象锁,要等到执行notify()方法的线程将程序执行完,也就是退出同步代码块之后才会释放对象锁。
3.阻塞式队列代码演示
阻塞式队列:ArrayBlockingQueue 类
package com.zg;
/**
* 采用顺序表实现的阻塞式队列
* //1.首先解决线程安全问题:经过分析,在方法上面见synchronized;
* //2.解决通知机制:
* 调offer的有可能去唤醒poll,调用poll的有可能去唤醒offer
*/
/**
* 生产者只调用offer
* 消费者只调用poll
*/
public class ArrayBlockingQueue {
private Integer[] array = new Integer[5];
private int size = 0;
private int headIndex = 0;//队列中的第一个元素的下标
private int rearIndex = 0;//队尾中,下一个可以放入元素的下标(也就是队尾元素所在下标的下一个)
public synchronized boolean offer(Integer e) throws InterruptedException {
//临界区开始
while (size >= array.length){
//满了
this.wait();//Object.wait();//有可能你醒过来,条件还没有满足,因为不知道谁唤醒的,所以使用while
}
array[rearIndex] = e;
rearIndex++;
if (rearIndex == array.length){
rearIndex = 0;
}
size++;
notifyAll();//大赦天下
//临界区结束
return true;
}
public synchronized Integer poll() throws InterruptedException {
while (size <= 0){
wait();//有可能你醒过来,条件还没有满足,因为不知道谁唤醒的,所以使用while
}
Integer e = array[headIndex];
headIndex++;
if (headIndex == array.length){
headIndex = 0;
}
size--;
notifyAll();//大赦天下
return e;
}
}
生产者—消费者类:QueueDemo类
package com.zg;
public class QueueDemo {
static ArrayBlockingQueue queue = new ArrayBlockingQueue();
//生产者
static class Producer extends Thread{
@Override
public void run() {
setName("生产者");
while(true){
try {
queue.offer(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
//消费者
static class Consumer extends Thread{
@Override
public void run() {
setName("消费者");
try {
queue.poll();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
for (int i = 0;i < 5;i++){
Thread t1 = new Producer();//生产者
t1.start();
}
for (int i = 0;i < 5;i++){
Thread t = new Consumer();//消费者
t.start();
}
}
}