使用wait和notify去模拟Queue(队列)
BlockingQueue:
顾名思义,首先它是一个队列,并且支持阻塞的机制,阻塞地放入和得到数据.我们要实现LinkedBlockingQueue下面的两个简单的方法put和take.
put(anObjct):把anObject加到BlockingQueue里面,如果BlockingQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间 再继续, take:取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.
看代码的实现:
public class MyQueue {
// 1.需要一个承装元素的集合
private final LinkedList<Object> list = new LinkedList<Object>();
// 2.需要一个计数器(统计加入list集合的个数)
private AtomicInteger count = new AtomicInteger(0);
// 3.需要指定上限和下限
private final int minSize = 0;
private final int maxSize;
// 4.在构造方法中指定maxSize
public MyQueue(int maxSize) {
this.maxSize = maxSize;
}
//5.初识化一个对象,用于加锁
private Object lock = new Object();
public void put(Object obj) {
synchronized (lock) {
while(count.get() == this.maxSize) { //当前的容器已经满了
try {
lock.wait(); // 线程等待
} catch (InterruptedException e) {
e.printStackTrace();
}
}
list.add(obj); // 添加元素
count.incrementAndGet(); // 计数器递增
lock.notify(); // 已经加了一个元素 等待着的线程可以拿元素了 唤醒别的等待的线程
System.out.println("新加入的元素为:" + obj);
}
}
public Object take() {
Object ret = null;
synchronized (lock) {
while(count.get() == this.minSize) { // 当前的容器的空的,take()方法要阻塞
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 移除元素操作
ret = list.removeFirst();
//计数器递减
count.decrementAndGet();
//唤醒另外一个线程 想加元素的阻塞的线程
lock.notify();
}
return ret;
}
public int getSize() {
return this.count.get();
}
public static void main(String[] args) {
MyQueue mQueue = new MyQueue(5);
mQueue.put("a");
mQueue.put("b");
mQueue.put("c");
mQueue.put("d");
mQueue.put("e");
new Thread(()->{
mQueue.put("f");
mQueue.put("g");
},"t1").start();;
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(()->{
mQueue.take();
}).start();
}
}
需要注意的地方是,在唤醒线程的时候,要用对象锁去唤醒,如果直接使用notify()的话,是会有问题的.包跑异常
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)