Java阻塞队列详解
1.什么是阻塞队列
阻塞队列–BlockingQueue,它是一个接口,
public interface BlockingQueue
BlcokingQueue继承了Queue接口,是队列的一种,Queue和BlockingQueue都是在Java5中加入的,BlockingQueue是线程安全的,我们在很多场景下都可以利用线程安全的队列来优雅地解决我们业务自身的线程安全问题。
Java提供的线程安全的队列(也成为并发队列)主要分为阻塞队列和非阻塞队列俩大类。
阻塞队列的典型例子就是BlockingQueue接口的实现类,主要有6种实现:ArrayBlcokingQueue,LinkedBlockingQueue,SynchronousQueue,DelayQueue,PriorityBlockingQueue和LinkedTransherQueue,它们各自有不同不同的特点。
非阻塞并发队列最典型的就是ConcurrentLinkedQueue,这个类不会让线程阻塞,利用CAS保证了线程安全。
从上图还可以看到Deque,就是双端队列,双端队列从头和尾都能添加和删除元素,而普通的Queue只能从一端进入,另一端出去。这是Queue和Deque最主要的区别,其它方面基本都差不多。
2.阻塞队列的特点
阻塞队列的特点就是阻塞两个字,哈哈哈哈。像是废话。阻塞功能使得生产者和消费者两端的能力得以平衡,当有任何一端速度过快时,阻塞队列便会把过快的速度降下来。最重要的两个方法:take()和put();
take()
take方法的功能是获取并移除队列的头节点,通常在队列里有数据的时候是可以正常移除的,当队列里无数据,则阻塞,直到队列里面有数据。一旦有数据了,就立刻解除阻塞状态,并且获取到数据 put()
put方法插入元素时,如果队列没有满可以正常插入,如果队列满了,则阻塞,直到队列里面有了空闲空间,就会消除阻塞状态,并把数据添加进去。
阻塞队列容量问题
阻塞队列分为两种有界和无界。无界队列意味着里面可以容纳非常多的元素,例如LinkedBlcokingQueue的上限是Integer.MAX_VALUE。学过Java的人都知道这个数其实挺大的。但有界队列例如ArrayBlockingQueue如果队列满了,也不会扩容。
3.阻塞队列常用方法
在阻塞队列中有很多方法,而且都非常相似,这里我把常用的8个方法总结了一下以添加、删除为主。主要分为三类:
抛出异常:add、remove、element
返回结果但是不抛出异常:offer、poll、peek、
阻塞:take、put、
3.1 抛出异常:add、remove、element
add方法是往队列里面添加一个元素,如果队列满了,就会抛出异常来提示我们队列已满。
public static void main(String[] args) { BlockingQueueblockingQueue=new ArrayBlockingQueue<>(2); blockingQueue.add(1); blockingQueue.add(1); blockingQueue.add(1); }
这里我们指定队列容量为2,并且尝试加入3个值。超过了容量上限就会报IllegalStateException的错误。