模拟Queue

使用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)

猜你喜欢

转载自blog.csdn.net/qq_38200548/article/details/80173366