Java 中的队列 Queue
一、队列的定义
我们都知道队列(Queue)是一种先进先出(FIFO)的数据结构,Java中定义了java.util.Queue接口用来表示队列。Java中的Queue与List、Set属于同一个级别接口,它们都是继承于Collection接口。
Java中还定义了一种双端队列java.util.Deque,我们常用的LinkedList就是实现了Deque接口。
下面我们看一下类的定义:
Queue & 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中对于队列的实现分为非阻塞和阻塞两种。
$ 非阻塞队列分为如下:
LinkedList
LinkedList是双相链表结构,在添加和删除元素时具有比ArrayList更好的性能。但在 Get 与 Set 方面弱于ArrayList。当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比。PriorityQueue
PriorityQueue维护了一个有序列表,存储到队列中的元素会按照自然顺序排列。当然,我们也可以给它指定一个实现了
java.util.Comparator接口的排序类来指定元素排列的顺序。ConcurrentLinkedQueue
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)机制。
下面简单介绍一下其中常用的方法:
- add 增加一个元索 如果队列已满,则抛出一个IIIegaISlabEepeplian异常
- remove 移除并返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
- element 返回队列头部的元素 如果队列为空,则抛出一个NoSuchElementException异常
- offer 添加一个元素并返回true 如果队列已满,则返回false
- poll 移除并返问队列头部的元素 如果队列为空,则返回null
- peek 返回队列头部的元素 如果队列为空,则返回null
- put 添加一个元素 如果队列满,则阻塞
- take 移除并返回队列头部的元素 如果队列为空,则阻塞
三、示例
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){
}
}
}
Java 中的队列 Queue的更多相关文章
- Java中的队列Queue,优先级队列PriorityQueue
队列Queue 在java5中新增加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口. Queue使用时要尽量避免Collecti ...
- Java中使用队列Queue
示例代码: Queue<Integer> queue = new LinkedList<Integer>(); for (int i = 1; i <= 100; i + ...
- java中有界队列的饱和策略(reject policy)
文章目录 AbortPolicy DiscardPolicy DiscardOldestPolicy CallerRunsPolicy 使用Semaphore java中有界队列的饱和策略(rejec ...
- java中使用队列:java.util.Queue (转)
Queue接口与List.Set同一级别,都是继承了Collection接口.LinkedList实现了Queue接 口.Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类 ...
- java中的各种Queue
java中的各种并发Queue可以归为以下的几种: ConcurrentLinkedQueue: 一个由链表结构组成的非阻塞队列 ArrayBlockingQueue :一个由数组结构组成的有界阻塞队 ...
- 一篇图看清Java中的各种Queue
说到数据结构,我们大概可以列出这么几个:数组,链表,栈,队列,集合,哈希表. 其中 队列 作为一个常用的数据结构,在Java中也有各种形式的实现. 顶级接口为java.util.queue. java ...
- Java线程安全队列Queue实现原理
原文链接:https://www.cnblogs.com/DreamRecorder/p/9223016.html 在Java多线程应用中,队列的使用率很高,多数生产消费模型的首选数据结构就是队列.J ...
- Java中的队列:java.util.Queue接口
队列是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作. Queue接口与List.Set同一级别,都是继承了Collection接口.Linked ...
- java中使用队列:java.util.Queue
在java5中新添加了java.util.Queue接口,用以支持队列的常见操作.该接口扩展了java.util.Collection接口.Queue使用时要尽量避免Collection的add()和 ...
随机推荐
- DOS下如何打开程序
cd c: #先切回主盘,因为最开始在C:\Users\Administrator这个目录下 cd “指定文件所在的盘:” #切换到文件所在盘 print "文件目录&quo ...
- 线段树区间覆盖 蛤玮打扫教室(zzuli 1877)
http://acm.zzuli.edu.cn/zzuliacm/problem.php?id=1877 Description 现在知道一共有n个机房,算上蛤玮一共有m个队员,教练做了m个签,每 ...
- ubuntu下mysql远程连接
第一步: vim /etc/mysql/my.cnf找到bind-address = 127.0.0.1 注释掉这行,如:#bind-address = 127.0.0.1 ...
- noip第27课作业
1. 繁忙的都市 [问题描述] 城市C是一个非常繁忙的大都市,城市中的道路十分的拥挤,于是市长决定对其中的道路进行改造.城市C的道路是这样分布的:城市中有n个交叉路口,有些交叉路口之间有道路相连,两个 ...
- Hdu2389 Rain on your Parade (HK二分图最大匹配)
Rain on your Parade Problem Description You’re giving a party in the garden of your villa by the sea ...
- 3D打印软件工具
切片与工艺规划(打印)软件: 3D打印中另外两个重要的步骤(切片和打印)中可以用到的一些开源,免费的软件和应用 Cura 开源, 免费 Python ...
- 解决UNIGUI字体太小的问题
解决UNIGUI字体太小的问题 Unigui运行在chrome浏览器下可以有最佳的效果,但用ie打开用unigui做的项目会发现字体明显小一截,可以用自定义css来解决这个问题. 可以在UniServ ...
- [Leedcode 169]Majority Element
1 题目描述 Given an array of size n, find the majority element. The majority element is the element that ...
- ipad协议
getLoginQRCode (获取登录二维码)CheckLoginQRCode(检测扫码状态)ManualAuth(扫码登录)ManualAuth(62数据登录)ManualAuth(账号密码登录) ...
- Spring AOP 源码分析系列文章导读
1. 简介 前一段时间,我学习了 Spring IOC 容器方面的源码,并写了数篇文章对此进行讲解.在写完 Spring IOC 容器源码分析系列文章中的最后一篇后,没敢懈怠,趁热打铁,花了3天时间阅 ...