咱们都知道队列(Queue)是一种先进先出(FIFO)的数据结构,Java中定义了java.util.Queue
接口用来表示队列。Java中的Queue
与List
、Set
属于同一个级别接口,它们都是继承于Collection
接口。java
Java中还定义了一种双端队列java.util.Deque
,咱们经常使用的LinkedList
就是实现了Deque
接口。数组
下面咱们看一下类的定义:安全
public interface Queue<E> extends Collection<E> { boolean add(E e); boolean offer(E e); E remove(); E poll(); E element(); E peek(); }
public interface Deque<E> extends Queue<E> { void addFirst(E e); void addLast(E e); boolean offerFirst(E e); boolean offerLast(E e); E removeFirst(); E removeLast(); E pollFirst(); E pollLast(); E getFirst(); E getLast(); E peekFirst(); E peekLast(); boolean removeFirstOccurrence(Object o); boolean removeLastOccurrence(Object o); // *** Queue methods *** boolean add(E e); boolean offer(E e); E remove(); E poll(); E element(); E peek(); // *** Stack methods *** void push(E e); E pop(); // *** Collection methods *** boolean remove(Object o); boolean contains(Object o); public int size(); Iterator<E> iterator(); Iterator<E> descendingIterator(); }
Java中对于队列的实现分为非阻塞和阻塞两种。数据结构
LinkedListdom
LinkedList
是双相链表结构,在添加和删除元素时具备比ArrayList
更好的性能。但在 Get 与 Set 方面弱于ArrayList
。固然,这些对比都是指数据量很大或者操做很频繁的状况下的对比。ide
PriorityQueue性能
PriorityQueue维护了一个有序列表,存储到队列中的元素会按照天然顺序排列。固然,咱们也能够给它指定一个实现了 java.util.Comparator
接口的排序类来指定元素排列的顺序。线程
ConcurrentLinkedQueuecode
ConcurrentLinkedQueue
是基于连接节点的而且线程安全的队列。由于它在队列的尾部添加元素并从头部删除它们,因此只要不须要知道队列的大小 ConcurrentLinkedQueue
对公共集合的共享访问就能够工做得很好。收集关于队列大小的信息会很慢,须要遍历队列。对象
阻塞队列定义在了java.util.concurrent
包中,java.util.concurrent.BlockingQueue
继承了Queue
接口,它有 5 个实现类,分别是:
ArrayBlockingQueue
一个内部由数组支持的有界队列。初始化时必须指定队列的容量,还能够设置内部的ReentrantLock是否使用公平锁。可是公平性会使你在性能上付出代价,只有在的确很是须要的时候再使用它。它是基于数组的阻塞循环队列,此队列按 FIFO(先进先出)原则对元素进行排序。
它的思想就是若是BlockQueue是空的,那么从BlockingQueue取东西的操做将会被阻断进入等待状态,直到BlockingQueue进了东西才会被唤醒。一样,若是BlockingQueue是满的,任何试图往里存东西的操做也会被阻断进入等待状态,直到BlockingQueue里有空间才会被唤醒继续操做。
LinkedBlockingQueue
一个内部由连接节点支持的可选有界队列。初始化时不须要指定队列的容量,默认是Integer.MAX_VALUE
,也能够当作容量无限大。此队列按 FIFO(先进先出)排序元素 。
PriorityBlockingQueue
一个内部由优先级堆支持的无界优先级队列。PriorityBlockingQueue是对 PriorityQueue的再次包装,队列中的元素按优先级顺序被移除。
DelayQueue
一个内部由优先级堆支持的、基于时间的调度队列。队列中存放Delayed元素,只有在延迟期满后才能从队列中提取元素。当一个元素的getDelay()方法返回值小于等于0时才能从队列中poll中元素,不然poll()方法会返回null。
SynchronousQueue
一个利用 BlockingQueue 接口的简单汇集(rendezvous)机制。
下面简单介绍一下其中经常使用的方法:
package com.ysc.thread; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; public class BlockingQueueTest { public static void main(String[] args) { final BlockingQueue queue = new ArrayBlockingQueue(3); for(int i=0;i<2;i++){ new Thread(){ public void run(){ while(true){ try { Thread.sleep((long)(Math.random()*1000)); System.out.println(Thread.currentThread().getName() + "准备放数据!"); queue.put(1); System.out.println(Thread.currentThread().getName() + "已经放了数据," + "队列目前有" + queue.size() + "个数据"); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } new Thread(){ public void run(){ while(true){ try { //将此处的睡眠时间分别改成100和1000,观察运行结果 Thread.sleep(1000); System.out.println(Thread.currentThread().getName() + "准备取数据!"); queue.take(); System.out.println(Thread.currentThread().getName() + "已经取走数据," + "队列目前有" + queue.size() + "个数据"); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); } }
package com.ysc.thread; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class BlockingQueueCondition { public static void main(String[] args) { ExecutorService service = Executors.newSingleThreadExecutor(); final Business business = new Business(); service.execute(new Runnable(){ @Override public void run() { for(int i=0;i<50;i++){ business.sub(); } } }); for(int i=0;i<50;i++){ business.main(); } } } class Business { BlockingQueue subQueue = new ArrayBlockingQueue(1); BlockingQueue mainQueue = new ArrayBlockingQueue(1); //这里是匿名构造方法,只要new一个对象都会调用这个匿名构造方法,它与静态块不一样,静态块只会执行一次, //在类第一次加载到JVM的时候执行 //这里主要是让main线程首先put一个,就有东西能够取,若是不加这个匿名构造方法put一个的话程序就死锁了 { try { mainQueue.put(1); } catch (InterruptedException e) { e.printStackTrace(); } } public void sub(){ try { mainQueue.take(); for(int i=0;i<10;i++){ System.out.println(Thread.currentThread().getName() + " : " + i); } subQueue.put(1); } catch (Exception e){ } } public void main() { try { subQueue.take(); for(int i=0;i<5;i++){ System.out.println(Thread.currentThread().getName() + " : " + i); } mainQueue.put(1); } catch (Exception e){ } } }