java线程(7)——阻塞队列BlockingQueue

回顾:


阻塞队列,英文名叫BlockingQueue。首先他是一种队列,联系之前Java基础——集合中介绍的Queue与Collection,我们就很容易开始今天的阻塞队列的学习了。来看一下他们的接口定义:

Queue:

(方法很简单,就不一一注释解释其作用了。)

public interface Queue<E> extends Collection<E> {
   
    boolean add(E e);

    boolean offer(E e);

    E remove();

    E poll();

    E element();
  
    E peek();
}

BlockingQueue:

      因为是继承自Queue,方法基本类似,就不再写了。主要方法有三个:add,remove,element(用于检查)。

      那到底什么是阻塞队列呢?联系前面java线程——模拟生产者与消费者的例子,在篮子中没有馒头时,生成者要放入馒头消费者才能食用;在篮子里装满馒头时,生产者就不能继续生产了,要等人去吃。阻塞队列就是生产者存放馒头的容器,消费者从中取出元素,也就是那个篮子。

public interface BlockingQueue<E> extends Queue<E> {
......
 }

      BlockingQueue的实现类有很多,这里介绍一个很简单的ArrayBlockingQueue。他是一个数据结构组成的阻塞队列,按照FIFO先进先出的方式排序。




继续来看他的定义,下面只列举了常用的两个方法:

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
			
	//放入元素
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
	
	
	//取元素
	 public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return dequeue();
        } finally {
            lock.unlock();
        }
    }
		}
		
		
		
		


来个例子:

//Capacity为3的阻塞队列
		final BlockingQueue queue = new  ArrayBlockingQueue(3);
		for (int i = 0; i < 2; i++) {
			//1、放馒头线程
			new Thread() {

				@Override
				public void run() {
					while (true) {

						try {
							Thread.sleep((long) (Math.random() * 10000));
							System.out.println(Thread.currentThread().getName()
									+ "准备放馒头!");
							//每次放入一个馒头
							queue.put(1);
							System.out.println(Thread.currentThread().getName()
									+ "已经放了馒头," + "队列目前有" + queue.size()
									+ "个馒头");
						} catch (InterruptedException e) {

							e.printStackTrace();
						}
					}
				}

			}.start();
		}
		//2、取馒头线程
		new Thread() {

			@Override
			public void run() {
				while (true) {
					try {

						Thread.sleep((long) (Math.random() * 10000));
						System.out.println(Thread.currentThread().getName()
								+ "准备取馒头!");
						//拿走一个
						queue.take();
						System.out.println(Thread.currentThread().getName()
								+ "已经取走馒头," + "队列目前有" + queue.size() + "个馒头");
					} catch (InterruptedException e) {

						e.printStackTrace();
					}
				}
			}

		}.start();

	}


部分执行结果:



对比:

       和之前手动实现生产者消费者的例子相比,这次的实现就简单多了。不再需要去管篮子里的“取”和“放”的操作,不用关心线程的同步互斥问题,不用关心篮子是空了还是满了。只需要简单的调用put或take方法即可,把复杂的阻塞问题教给BlockingQueue去处理,但是原理还是一样的。

原文地址:https://www.cnblogs.com/saixing/p/6730215.html