并发编程基础07-使用wait和notify模拟LinkedBlockingQueue

版权声明:博观而约取,厚积而薄发。 https://blog.csdn.net/BruceLiu_code/article/details/88375381

BlockingQueue:顾名思义,首先它是一个队列,然后支持阻塞机制。阻塞的放入和得到的数据。如果我们要实现LinkedBlockingQueue,那么最起码要实现两个最为基础的方法:put和tack。

  • put:把anObject加入到BlockingQueue中,如果队列中没有空间,则调用此方法的线程被阻塞,直到BlockingQueue中有可用的空间再继续加入。
  • tabk:获取BlockingQueue中排在首位的对象,弱BlockingQueue为空,则阻塞进入等待的状态。直到BlockingQueue有新的数据被加入。

示例:

/**
 * 使用wait和notify模拟BlockingQueue
 * @author bruceliu
 * @create 2019-03-10 10:21
 */
public class MyQueue {

    //1.定义一个空的元素集合
    private LinkedList<Object> list=new LinkedList<Object>();

    //2.定义一个计数器
    private AtomicInteger count=new AtomicInteger();

    //3.定义上限和下限
    private final int minSize=0;
    private int maxSize;

    //4.定义构造方法
    public MyQueue(int size){
        this.maxSize=size;
    }

    //5.初始化一个对象,用作加锁
    private  final Object lock=new Object();

    //put(anObject): 把anObject加到BlockingQueue里,如果BlockQueue没有空间,则调用此方法的线程被阻断,直到BlockingQueue里面有空间再继续.
    public void put(Object object){
        synchronized (lock){
            while(count.get()==this.maxSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1.加入元素
            list.add(object);
            //2.计数器累加
            count.incrementAndGet();
            //3.通知另外一个线程 唤醒
            lock.notify();
            System.out.println("新加入的元素为:"+object);
        }
    }

    //take: 取走BlockingQueue里排在首位的对象,若BlockingQueue为空,阻断进入等待状态直到BlockingQueue有新的数据被加入.
    public Object take(){
        Object object=null;
        synchronized (lock){
            while(count.get()==this.minSize){
                try {
                    lock.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            //1.移除元素
            object=list.removeFirst();
            //2.计数器递减
            count.decrementAndGet();
            //3.唤醒另外一个线程
            lock.notify();
        }
        return object;
    }

    //获取集合大小
    public  int getSize(){
        return this.count.get();
    }
}

测试:

/**
 * 测试自定义阻塞队列
 * @author bruceliu
 * @create 2019-03-10 10:48
 */
public class TestMyQueue {

    public static void main(String[] args) {

        final MyQueue mq=new MyQueue(5);
        mq.put("a");
        mq.put("b");
        mq.put("c");
        mq.put("d");
        mq.put("e");

        System.out.println("当前容器的长度是:"+mq.getSize());

        Thread t1=new Thread(new Runnable() {
            public void run() {
                mq.put("f");
                mq.put("g");
            }
        },"t1");

        t1.start();


        Thread t2=new Thread(new Runnable() {
            public void run() {
                Object o1=mq.take();
                System.out.println("移除的元素为:"+o1);

                Object o2=mq.take();
                System.out.println("移除的元素为:"+o2);
            }
        },"t2");


        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        t2.start();

    }
}

事实上,在JavaJDK中已经有了LinkedBlockingQueue这样一个阻塞队列,在此模拟一下是方便更好的理解阻塞队列。
在这里插入图片描述
如果有兴趣,可以看看LinkedBlockingQueue的源码。

猜你喜欢

转载自blog.csdn.net/BruceLiu_code/article/details/88375381