JDK源码之BlockingQueue(源码注释)

在多线程环境中,经常会用到“生产者-消费者”模式,负责生产的线程要把数据交给负责消费的线程,那么就需要一个数据共享容器,由生产者存入,消费者取出,这个时候就需要队列(Queue)来实现该仓库。

在Java Concurrent包发布之前,生产消费模式需要我们自己维护阻塞队列,但是自己实现的队列往往会在性能和安全方面存在缺陷,Java Concurrent包提供了BlockingQueue接口及实现类来实现生产者-消费者模型。

Java.util.concurrent.BlockingQueue,是一个阻塞队列接口。

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

BlockingQueue的核心方法

抛出异常 返回特定值 无限阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
查询 element() peek()

还有几个其他的方法:

  1. int remainingCapacity();
    此方法返回的是在理想情况下(没有内存或资源的约束)可以接受而不会阻塞的元素的数量。返回的值 = 队列的初始容量 - 该队列当前size
  2. public boolean contains(Object o);
    返回该队列是否包含某个对象
  3. int drainTo(Collection c);
  4. int drainTo(Collection c, int maxElements);
    3.4两个方法差不多,方法3在接口的实现类上都是调用了方法4的实现方法(仅限于ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue这三个实现类),一次性从BlockingQueue获取所有可用的数据对象(可以指定获取数据的个数),通过该方法,可以提升获取数据效率,不需要多次分批加锁或释放锁。

BlockingQueue接口方法在抽象类AbstractQueue的实现:
①add(E)方法用于入队,入队失败则抛出队列已满异常,反之返回true

public boolean add(E e) {
		// 这里调用offer实现add,如果插入失败则返回Queue full异常
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

②remove()方法用于移除队头元素

public E remove() {
		// 调用poll()
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

③element()方法用于查看队头元素

public E element() {
		// 调用peek()
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

可以发现,插入移除查询这三个方法的具体实现是交由 offer(e)\poll()\peek()负责,在BlockingQueue的实现类里,通过重写这几个方法来达到多线程安全的目的。

相关链接:
ArrayBlockingQueue源码解析
LinkedBlockingQueue源码解析

附:
因为用到了BlockingQueue接口类和AbstractQueue抽象类,这里顺便复习一下

接口类和抽象类的区别
1.抽象类可以有构造方法,接口中不能有构造方法。
2.抽象类中可以有普通成员变量,接口中没有普通成员变量
3.抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
4. 抽象类中的抽象方法的访问类型可以是public,protected,但接口中的抽象方法只能是public类型的,并且默认即为public abstract类型。
5. 抽象类中可以包含静态方法,接口中不能包含静态方法(jdk1.8之后接口可以包含静态方法)
6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只能是public static final类型,并且默认即为public static final类型。
7. 一个类可以实现多个接口,但只能继承一个抽象类。
参考:https://blog.csdn.net/qq_41933748/article/details/82670072

什么时候用抽象类和接口
1.若果你拥有一些方法并且想让他们中的一些有默认实现,那就用抽象类。
2.如果你想实现多重继承,那么必须使用接口。由于 java 不支持多继承,子类不能继承多个父类,但是可以实现多个接口,因此你可以使用接口来实现它。
3.如果基本基本功能在不断变化,那么就需要使用抽象类。如果不断改变基本功能并且使用接口,那么所有实现类都需要改变。
参考:https://www.cnblogs.com/leeego-123/p/11378108.html

接口是设计的结果,抽象类是重构的结果。

你可能感兴趣的:(JDK源码,java,queue,队列)