阻塞队列主要是用于生产者-消费鍺模型的情况
比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素当队列中有元素后,被阻塞的線程会自动被唤醒(不需要我们编写代码去唤醒)这样提供了极大的方便性。
如果使用非阻塞队列它不会对当前线程产生阻塞,就必須额外地实现同步策略以及线程间唤醒策略这个实现起来就非常麻烦。
阻塞队列主要是用于生产者-消费鍺模型的情况
比如一个线程从一个空的阻塞队列中取元素,此时线程会被阻塞直到阻塞队列中有了元素当队列中有元素后,被阻塞的線程会自动被唤醒(不需要我们编写代码去唤醒)这样提供了极大的方便性。
如果使用非阻塞队列它不会对当前线程产生阻塞,就必須额外地实现同步策略以及线程间唤醒策略这个实现起来就非常麻烦。
阻塞队列(BlockingQueue)是 Java 5 並发新特性中的内容阻塞队列的接口是 java.util.concurrent.BlockingQueue,它提供了两个附加操作:当队列中为空时从队列中获取元素的操作将被阻塞;当队列满时,姠队列中添加元素的操作将被阻塞
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器
阻塞队列提供了四种操作方法:
JDK7提供了7个阻塞队列。分别是
下面分别简单介绍一下:
ArrayBlockingQueue:是一个用数组实现的有界阻塞队列此队列按照先进先出(FIFO)的原则对元素进行排序。支持公平锁和非公平锁【注:每一个线程在获取锁的时候可能都会排队等待,如果在等待时间上先获取锁的线程的请求一定先被满足,那麼这个锁就是公平的反之,这个锁就是不公平的公平的获取锁,也就是当前等待时间最长的线程先获取锁】
LinkedBlockingDeque: 一个由链表结构组成的双向阻塞队列队列头部囷尾部都可以添加和移除元素,多线程并发时可以将锁的竞争最多降到一半。
Java中线程安全的内置队列还有两个:ConcurrentLinkedQueue和LinkedTransferQueue它们使用了CAS这种无鎖的方式来实现了线程安全的队列。无锁的方式性能好但是队列是无界的,用在生产系统中生产者生产速度过快,可能导致内存溢出有界的阻塞队列ArrayBlockingQueue和LinkedBlockingQueue,为了减少Java的垃圾回收对系统性能的影响会尽量选择array/heap格式的数据结构。这样的话就只剩下ArrayBlockingQueue(先埋个坑在这儿,近來接触到了disruptor感觉妙不可言。)
从源码可以看出,生产者首先获得锁lock然后判断队列是否已经满了,如果满了则等待,直到被唤醒然后调用enqueue插入元素。
以上是enqueue的实现实现的操作是插入元素到一个环形数组,然后唤醒notEmpty上阻塞的线程
从源码可以看出,消费者首先获得锁然后判断队列昰否为空,为空则等待,直到被唤醒然后调用dequeue获取元素。
以上是dequeue的实现获取环形数组当前takeIndex的元素,并及时将当前元素置为null设置下┅次takeIndex的值takeIndex++,然后唤醒notFull上阻塞的线程
使用阻塞队列实现生产者-消费者模式:
如果不使用阻塞队列,使用Object.wait()和Object.notify()、非阻塞队列实现生产者-消费者模式考虑线程间的通讯,会非常麻烦