模拟实现一个阻塞队列
背景:
最近在跟白老师学习,布置了一个作业,就是要自己写一个阻塞队列出来。
功能点:
开发出一个阻塞队列类,提供put()、take()方法。其中put()方法表示往队列里插入一个元素,如果队列容量不足,则等待,直到有空间为止。take()方法表示从队列里取出第一个元素,如果队列里没有元素,则等待,直到有元素为止。
知识点:
synchronized、wait()、notify()的使用
代码:
首先,是最核心的队列类:
package top.usjava.learn.springbootlearn.util;
import java.util.ArrayList;
import java.util.List;
/**
* 第一周作业:模拟实现一个阻塞队列
*
* @author Owen
* @date 2018/9/2 15:20
*/
public class MyBlockingQueue<T> {
/**
* 队列中的容器,用来放队列的元素
*/
private final List<T> list = new ArrayList<>();
/**
* 队列的最大容量值
*/
private final int maxSize;
/**
* 队列当前的元素个数
*/
private int size = 0;
/**
* 锁
*/
private final Object object = new Object();
public MyBlockingQueue(int maxSize) {
this.maxSize = maxSize;
}
/**
* 插入一个元素到队列里,如果空间不足,则等待,直到有空间位置
*
* @param t the element to add
* @throws InterruptedException if interrupted while waiting
*/
public void put(T t) throws InterruptedException {
synchronized (object) {
while (size == maxSize) {
object.wait();
}
list.add(t);
size++;
object.notify();
System.out.println("queue size:"+size+" "+System.currentTimeMillis());
}
}
/**
* 移除队列中第一个元素,如果当前队列没有元素,则一直等待,直到有元素位置。
*
* @return the head of this queue
* @throws InterruptedException if interrupted while waiting
*/
public T take() throws InterruptedException{
T t;
synchronized (object) {
while (size == 0) {
object.wait();
}
t = list.remove(0);
size--;
System.out.println("queue size:"+size+" "+System.currentTimeMillis());
//这里故意休眠500ms用于观察一定要take后才能继续put
Thread.sleep(500L);
object.notify();
}
return t;
}
}
其次,建一个Bean类,用来稍后测试用:
package top.usjava.learn.springbootlearn.vo;
/**
* 猪类
*
*
* @author Owen
* @date 2018/9/2 17:00
*/
public class Pig {
/**
* 名称
* */
String name;
/**
* 生日
* */
long bornTime;
public Pig(String name, long bornTime) {
this.name = name;
this.bornTime = bornTime;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public long getBornTime() {
return bornTime;
}
public void setBornTime(long bornTime) {
this.bornTime = bornTime;
}
}
测试类:
package top.usjava.learn.springbootlearn.testmain;
import top.usjava.learn.springbootlearn.util.MyBlockingQueue;
import top.usjava.learn.springbootlearn.vo.Pig;
/**
* @Description: 测试MyBlockingQueue
* @author Owen
* @date 2018/9/2 16:36
*/
public class TestMyBlockingQueue {
public static void main(String[] args) throws InterruptedException {
//先初始化队列,并放入5个元素,这时,队列装满了
MyBlockingQueue<Pig> employeeMyBlockingQueue = new MyBlockingQueue<>(5);
employeeMyBlockingQueue.put(new Pig("A",System.currentTimeMillis()));
employeeMyBlockingQueue.put(new Pig("B",System.currentTimeMillis()));
employeeMyBlockingQueue.put(new Pig("C",System.currentTimeMillis()));
employeeMyBlockingQueue.put(new Pig("D",System.currentTimeMillis()));
employeeMyBlockingQueue.put(new Pig("E",System.currentTimeMillis()));
//新的存放操作一开始会阻塞,直到下面第二个线程提取一个元素后,才有空间,才能存放成功
Thread t1 = new Thread(()->{
try {
employeeMyBlockingQueue.put(new Pig("F",System.currentTimeMillis()));
System.out.println("存放F成功");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t1.start();
//提取一个元素出来
Thread t2 = new Thread(()->{
try {
Thread.sleep(2000L);
Pig pig = employeeMyBlockingQueue.take();
System.out.println("取出了元素:"+pig.getName());
} catch (InterruptedException e) {
e.printStackTrace();
}
});
t2.start();
}
}
运行结果:
从结果可以看出:
- 首先,程序往队列存放了5个元素
- 直到两秒后,先释放了一个A元素
- 又过了500ms后,F元素才插入成功
“取出了元素:A”之所以在最后才出现是系统优先执行t1线程的输出了。其实从前三点已经知道队列是先取出A再放入F的。
因此,模拟成功。有不正之处请多多指点。