Queue
一、Queue是什么
Queue是一种队列结构集合,用来储存将要进行处理的元素,一般会以FIFO的方式排序元素,但这不是必须的。比如优先级队列就是一个例外,优先级队列是以元素的值来排序。但是无论怎么样,每个queue的实现都必须制定它的排序属性。queue通常不定义元素的equal和hashCode
二、Queue的实现
1. 非阻塞
-
LinkedList 实现了Queue和AbstractQueue
-
PriorityQueue
PriorityQueue类 实质上维护了一个有序列表。加入到Queue中的元素根据他们天然排序(通过实现Comparable实现)或者根据传递给构造函数的Comparator实现来定位,它的增加操作不是原子操作,没有添加任何锁,所以它是线程不安全的。 -
ConcurrentLinkedQueue
ConcurrentLinkedQueue是基于链接节点的、线程安全的队列,并发访问不需要同步,
它是非阻塞队列,使用CAS非阻塞算法实现
推荐看看
1. 阻塞
java.util.concurrent中加入了BlockingQueue接口和五个阻塞队列,它实质上就是一种带有一点扭曲的FIFO数据结构。不是立即从队列添加或者删除元素,线程操作阻塞,直到有空间或元素可用 -
ArrayBlockingQueue :一个由数组支持的有界队列
-
LinkedBlockingQueue:一个由链表节点支持的可选有界的队列(固定线程 使用的就是它)
-
PriorityBlockingQueue:一个由优先级堆支持的无界优先级队列
-
DelayQueue: 一个由优先级堆的、基于时间的调度队列 (定时线程 使用的就是它)
-
SynchronousQueue:一个利用BlockingQueue接口的简单聚集机制(缓存线程 使用的就是它)
三、方法
返回 | 方法 | 说明 |
---|---|---|
boolean | add(E) | 添加元素,如果队列已满,抛出IllegalStateException |
boolean | offer(E) | 与add一样,add就是调用的offer方法 |
E | remove() | 移除并返回队列头部元素,如果队列为空则抛出NoSuchElementException |
E | element() | 返回队列头部元素,如果队列为空则抛出NoSuchElementException |
E | poll() | 移除并返回队列头部元素,如果队列为空则返回null |
E | peek() | 返回队列头部元素 如果队列为空返回null |
void | put(E) | 添加一个元素 如果队列满了 则阻塞 |
E | take() | 移除并返回队列头部元素,如果队列为空 则阻塞 |
package along;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit;
import com.mysql.jdbc.TimeUtil;
public class javaTest {
public static void main(String[] args) {
//ArrayBlockingQueue
ArrayBlockingQueue<Integer> aq = new ArrayBlockingQueue<Integer>(10);
for(int i=0;i<11;i++){
//aq.add(i);
}
//java.lang.IllegalStateException: Queue full
//LinkedBlockingQueue 无界 有界
LinkedBlockingQueue<Integer> lq1 = new LinkedBlockingQueue<Integer>();
LinkedBlockingQueue<Integer> lq2 = new LinkedBlockingQueue<Integer>(10);
//PriorityBlockingQueue
PriorityBlockingQueue<Integer> pq = new PriorityBlockingQueue<Integer>();
pq.add(2);pq.add(8);pq.add(1);pq.add(22);
Integer i=null;
while((i = pq.poll()) != null){
System.out.println(i);
}
//1 2 8 22 按顺序排列
DelayQueue<DelayedTest> dq = new DelayQueue<DelayedTest>();
//这里传入的参数是毫秒 他会转换成秒 再加上当前系统时间
DelayedTest d1 = new DelayedTest(1, "111111111111111111111", 10000);
DelayedTest d2 = new DelayedTest(2, "222222222222222222222", 20000);
DelayedTest d3 = new DelayedTest(3, "333333333333333333333", 30000);
dq.add(d1);
dq.add(d2);
dq.add(d3);
try{
// System.out.println(dq.take());//元素被添加到队列 10秒后输出
// System.out.println(dq.take());//元素被添加到队列 20秒后输出
// System.out.println(dq.take());//元素被添加到队列 30秒后输出
}catch(Exception e){
System.out.println("error");
}
//SynchronousQueue 这个东西很神奇 它的作用是如果想add一个元素进去 必须有take在等待 也就是如果生产想要push必须等待消费者的take
SynchronousQueue<Integer> sq =new SynchronousQueue<>();
// sq.add(12);//没有线程take这里是没有办法加进去的
new Thread(new Runnable() {
public void run() {
try{
System.out.println("元素:"+sq.take());
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
//主线程等待2秒钟
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
new Thread(new Runnable() {
public void run() {
try{
sq.add(1111);
}catch(Exception e){
e.printStackTrace();
}
}
}).start();
//但是用put不会报错 他会等着take操作 没有take他不会put成功
try {
sq.put(1212);
} catch (InterruptedException e) {
e.printStackTrace();
}
/**
* iterator() 永远返回空,因为里面没东西。
* peek() 永远返回null。
* put() 往queue放进去一个element以后就一直wait直到有其他thread进来把这个element取走。
* offer() 往queue里放一个element后立即返回,如果碰巧这个element被另一个thread取走了,offer方法返回true,认为offer成功;否则返回false。
* offer(2000, TimeUnit.SECONDS) 往queue里放一个element但是等待指定的时间后才返回,返回的逻辑和offer()方法一样。
* take() 取出并且remove掉queue里的element(认为是在queue里的。。。),取不到东西他会一直等。
* poll() 取出并且remove掉queue里的element(认为是在queue里的。。。),只有到碰巧另外一个线程正在往queue里offer数据或者put数据的时候,该方法才会取到东西。否则立即返回null。
* poll(2000, TimeUnit.SECONDS) 等待指定的时间然后取出并且remove掉queue里的element,其实就是再等其他的thread来往里塞。
* isEmpty()永远是true。
* remainingCapacity() 永远是0。
* remove()和removeAll() 永远是false。
*/
// SynchronousQueue 内部没有容量,但是由于一个插入操作总是对应一个移除操作,反过来同样需要满足。
// 那么一个元素就不会再SynchronousQueue 里面长时间停留,一旦有了插入线程和移除线程,元素很快就从插入线程移交给移除线程。
//也就是说这更像是一种信道(管道),资源从一个方向快速传递到另一方 向。
//显然这是一种快速传递元素的方式,也就是说在这种情况下元素总是以最快的方式从插入着(生产者)传递给移除着(消费者),
//这在多任务队列中是最快处理任务的方式。
//在线程池里的一个典型应用是Executors.newCachedThreadPool()就使用了SynchronousQueue,
//这个线程池根据需要(新任务到来时)创建新的线程,如果有空闲线程则会重复使用,线程空闲了60秒后会被回收。
}
}