模拟Queue

xiaoxiao2021-02-28  45

使用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)
转载请注明原文地址: https://www.6miu.com/read-2625548.html

最新回复(0)