java 基础一 <队列>
接口 Queue<E>
boolean add(E e)
将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则抛出 IllegalStateException。
boolean offer(E e)
将指定的元素插入到此队列的尾部(如果立即可行且不会超过该队列的容量),在成功时返回 true,如果此队列已满,则返回 false。
peek()
获取但不移除此队列的头;如果此队列为空,则返回 null。
poll()
获取并移除此队列的头,如果此队列为空,则返回 null。
size()
返回此队列中的元素数量。
remove(Object o)
从队列中移除指定元素的单个实例(如果存在)。更确切地讲,如果此队列包含一个或多个满足 o.equals(e) 的元素 e,则移除一个这样的元素。
如果此队列包含指定元素(或者此队列由于调用而发生更改),则返回 true。
接口 BlockingQueue<E>
boolean |
add(E e) 将指定元素插入此队列中(如果立即可行且不会违反容量限制),成功时返回 true,如果当前没有可用的空间,则抛出 IllegalStateException。 |
boolean |
contains(Object o)
如果此队列包含指定元素,则返回 true。 |
int |
drainTo(Collection<? super E> c)
移除此队列中所有可用的元素,并将它们添加到给定 collection 中。 |
int |
drainTo(Collection<? super E> c,
int maxElements) 最多从此队列中移除给定数量的可用元素,并将这些元素添加到给定 collection 中。 |
boolean |
offer(E e)
将指定元素插入此队列中(如果立即可行且不会违反容量限制),成功时返回 true,如果当前没有可用的空间,则返回 false。 |
boolean |
offer(E e, long timeout,
TimeUnit unit)
将指定元素插入此队列中,在到达指定的等待时间前等待可用的空间(如果有必要)。 |
E |
poll(long timeout,
TimeUnit unit)
获取并移除此队列的头部,在指定的等待时间前等待可用的元素(如果有必要)。 |
void |
put(E e)
将指定元素插入此队列中,将等待可用的空间(如果有必要)。 |
int |
remainingCapacity()
返回在无阻塞的理想情况下(不存在内存或资源约束)此队列能接受的附加元素数量;如果没有内部限制,则返回 Integer.MAX_VALUE。 |
boolean |
remove(Object o)
从此队列中移除指定元素的单个实例(如果存在)。 |
E |
take()
获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。 |
1.ArrayBlockingQueue arrayBlockingQueue=new ArrayBlockingQueue(1024);
一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
公平性的理解:非公平性,即可能生产多个,才消费一个或者消费多个。 公平性:生产一个消费一个。
底层数据结构: 数组。
boolean offer(E e, long timeout, TimeUnit unit)
将指定的元素插入此队列的尾部,如果该队列已满,则在到达指定的等待时间之前等待可用的空间。
put(E e)
将指定的元素插入此队列的尾部,如果该队列已满,则等待可用的空间。
take()
获取并移除此队列的头部,在元素变得可用之前一直等待(如果有必要)。
public class ArrayBlockingQueueTest {
String TAG="ArrayBlockingQueueTest";
ArrayBlockingQueue<Integer> arrayBlockingQueue=new ArrayBlockingQueue<Integer>(1024);
int k=0;
boolean isRuning=true;
int max=10000_00;
public void main(){
Thread consumeThread=new Thread(new ConsumeThraed());
Thread productThread=new Thread(new ProductThraed());
consumeThread.start();
productThread.start();
}
//消费线程
class ConsumeThraed implements Runnable {
@Override
public void run() {
long startTime=System.currentTimeMillis();
Log.e(TAG, "消费开始:"+startTime);
while (true) {
if (!arrayBlockingQueue.isEmpty()) {
int data = arrayBlockingQueue.poll();
// Log.e(TAG, "消费产品编号:"+data);
}else{
if(!isRuning)
break;
}
}
long endTime=System.currentTimeMillis();
Log.e(TAG, "消费结束:"+endTime);
Log.e(TAG, "消费结束耗时:"+(endTime-startTime));
}
}
//生产线程
class ProductThraed implements Runnable{
@Override
public void run() {
long startTime=System.currentTimeMillis();
Log.e(TAG, "生产开始:"+startTime);
while (k<max) {
int data= k++;
arrayBlockingQueue.offer(data);
// Log.e(TAG, "生产产品编号:"+data);
}
long endTime=System.currentTimeMillis();
Log.e(TAG, "生产结束:"+endTime);
Log.e(TAG, "生产结束耗时:"+(endTime-startTime));
isRuning=false;
}
}
}
2.ConcurrentLinkedQueue
一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序,当多个线程共享访问一个公共 collection 时,ConcurrentLinkedQueue 是一个恰当的选择。此队列不允许使用 null 元素。
底层数据结构:链表
size()
需要小心的是,与大多数 collection 不同,此方法不是 一个固定时间操作。由于这些队列的异步特性,确定当前的元素数需要进行一次花费 O(n) 时间的遍历。
isEmpty()
如果此队列不包含任何元素,则返回 true。
public class ConcurrentLinkedQueueTest {
String TAG="ConcurrentLi...Test";
ConcurrentLinkedQueue<Integer> concurrentLinkedQueue=new ConcurrentLinkedQueue<Integer>();
int k=0;
boolean isRuning=true;
int max=10000_00;
public void main(){
Thread consumeThread=new Thread(new ConsumeThraed());
Thread productThread=new Thread(new ProductThraed());
consumeThread.start();
productThread.start();
}
//消费线程
class ConsumeThraed implements Runnable {
@Override
public void run() {
long startTime=System.currentTimeMillis();
Log.e(TAG, "消费开始:"+startTime);
while (isRuning) {
if (!concurrentLinkedQueue.isEmpty()) {
int data = concurrentLinkedQueue.poll();
// Log.e(TAG, "消费产品编号:"+data);
}else{
if(!isRuning)
break;
}
}
long endTime=System.currentTimeMillis();
Log.e(TAG, "消费结束:"+endTime);
Log.e(TAG, "消费耗时:"+(endTime-startTime));
}
}
//生产线程
class ProductThraed implements Runnable{
@Override
public void run() {
long startTime=System.currentTimeMillis();
Log.e(TAG, "生产开始:"+startTime);
while (k<max) {
int data= k++;
concurrentLinkedQueue.offer(data);
// Log.e(TAG, "生产产品编号:"+data);
}
long endTime=System.currentTimeMillis();
Log.e(TAG, "生产结束:"+endTime);
Log.e(TAG, "生产耗时:"+(endTime-startTime));
isRuning=false;
}
}
}
ArrayBlockingQueue 和 ConcurrentLinkedQueue 区别比较:
ArrayBlockingQueue:
1.底层数据结构是数组
2.size() 函数可以很快返回的当前列表的元素总数。
3.可以指定列队的空间
4.大并发数据速度比ConcurrentLinkedQueue慢
ConcurrentLinkedQueue
1.底层数据结构是列表
2.size() 每次获取需要重新遍历元素,比较耗时
3.无法指定列队空间,默认是int的最大值
4.大并发数据比ArrayBlockingQueue更加高效
备注:100万条数据
ArrayBlockingQueue插入需要2000毫秒左右
ConcurrentLinkedQueue插入需要750毫秒左右
3.DelayQueue
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。
当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0 的值时,将发生到期。 无法使用 take 或 poll 移除未到期的元素。size 方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。
peek()
获取但不移除此队列的头部;如果此队列为空,则返回 null。与 poll 不同,如果队列中没有到期元素可用,则此方法返回下一个将到期的元素(如果存在一个这样的元素)。
poll()
获取并移除此队列的头,如果此队列不包含具有已到期延迟时间的元素,则返回 null。
take()
获取并移除此队列的头部,在可从此队列获得到期延迟的元素之前一直等待。
public class DelayQueueTest {
String TAG="DelayQueueTest";
DelayQueue<Messages> delayQueue=new DelayQueue<Messages>();
public void main(){
Messages msg=new Messages("任务一",2,100);
Messages msg2=new Messages("任务二",1,2000);
Messages msg3=new Messages("任务三",4,1000);
Messages msg4=new Messages("任务四",3,1000);
delayQueue.add(msg);
delayQueue.add(msg2);
delayQueue.add(msg3);
delayQueue.add(msg4);
Thread taskThread=new Thread(new TaskThraed());
taskThread.start();
}
//任务线程
class TaskThraed implements Runnable {
@Override
public void run() {
Log.e(TAG, "run");
while (true) {
if (!delayQueue.isEmpty()) {
try {
Messages data = delayQueue.take();
Log.e(TAG, "执行任务:"+data.getMsg());
} catch (InterruptedException e) {
Log.e(TAG, "ex:"+ e.toString());
e.printStackTrace();
}
}else{
break;
}
}
Log.e(TAG, "任务线程已经退出!");
}
}
class Messages implements Delayed{
//优先级, 用于任务排序
int priority;
//消息
String msg;
//延迟时间
long delayedTime;
public Messages(String msg,int priority,long delayedTime){
this.msg=msg;
this.priority=priority;
//毫秒转换成纳秒,再加上现在的纳秒数
this.delayedTime= TimeUnit.NANOSECONDS.convert(delayedTime,TimeUnit.MILLISECONDS)+System.nanoTime();
}
public String getMsg(){
return msg;
}
public int getPriority(){
return priority;
}
@Override
public long getDelay(TimeUnit unit) {
long time = unit.convert(delayedTime-System.nanoTime(),TimeUnit.NANOSECONDS);
return time;
}
/*
给任务排序
1. 默认不排序同时进行,谁先到时间,谁先执行。
19:46:02.300 run
100 毫秒之后执行了任务一
19:46:02.398 执行任务:任务一
1000 毫秒之后执行了任务四和任务三
19:46:03.298 执行任务:任务四
19:46:03.298 执行任务:任务三
2000毫秒之后执行了任务二
19:46:04.298 执行任务:任务二
2. 排序之后,排序之后,就会安装顺序执行,继续后面的任务到时间了,也会等待前面的任务先执行完,在执行后面的任务
按照我们传递的优先级参数进行排序,2000毫秒之后全部同时执行,即使排序靠后的任务到时间了也不会立即执行,所以一般般都是按照延时是时间顺序排序。
19:53:16:556 run
19:53:18.554 执行任务:任务二
19:53:18.554 执行任务:任务一
19:53:18.554 执行任务:任务四
19:53:18.554 执行任务:任务三
*/
@Override
public int compareTo(Delayed o) {
Messages messages=(Messages) o;
if(getPriority()>messages.getPriority()){
return 1;
}else if(getPriority()<messages.getPriority()){
return -1;
}else{
return 0;
}
}
}
}
4.LinkedBlockingDeque
阻塞双端队列,可以同时操作两端的数据。
5.LinkedBlockingQueue
阻塞列队、一个基于已链接节点的、范围任意的 blocking queue。此队列按 FIFO(先进先出)排序元素。
6.PriorityBlockingQueue
一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作,据元素的自然顺序对其元素进行排序。也可以指定的比较器对其元素进行排序。
7.PriorityQueue
一个基于优先级堆的无界优先级队列。优先级队列的元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序
8.SynchronousQueue
一种阻塞队列,其中每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。同步队列没有任何内部容量,甚至连一个队列的容量都没有。不能在同步队列上进行 peek,因为仅在试图要移除元素时,该元素才存在;
除非另一个线程试图移除某个元素,否则也不能(使用任何方法)插入元素;也不能迭代队列,因为其中没有元素可用于迭代
浙公网安备 33010602011771号