1、并发Queue:在并发队列上JDK提供了两套实现,一套是以ConcurrentLinkedQueue为代表的高性能队列,一套是以BlockQueue接口为代表的阻塞队列,无论那种都继承queue。
2、ConcurrentLinkedQueue:适用于高并发下的队列,通过无锁的方式,实现了高并发下的高性能,通常ConcurrentLinkedQueue的性能高于BlockingQueue
。他是基于连接点的无界线程安全队列,遵循先进先出的原则,头是最先加入的,尾是最后加入的,并且不允许null值。
- 添加元素:add和offer,两个方法没有区别
- 获取元素:poll和peek,获取头元素,poll会删除,peek不会删除
//高性能无阻塞无界队列:ConcurrentLinkedQueue
ConcurrentLinkedQueue<String> q = new ConcurrentLinkedQueue<String>();
q.offer("a");
q.offer("b");
q.offer("c");
q.offer("d");
q.add("e");
System.out.println(q.poll()); //a 从头部取出元素,并从队列里删除
System.out.println(q.size()); //4
System.out.println(q.peek()); //b
System.out.println(q.size()); //4
3、BlockingQueue
BlockingQueue常用方法:
抛异常 | 特定值 | 阻塞 | 超时 | |
插入 | add(o) | offer(o) | put(o) | offer(o,timeout,timeunit) |
移除 | remave(o) | pull(o) | take(o) | poll(timeout,timeunit) |
检查 | element(o) | peek(o) |
四组不同的行为方式解释:
- 抛异常:如果试图的操作无法立即执行,抛一个异常。
- 特定值:如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
- 阻塞:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
- 超时:如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是true / false)。
ArrayBlockingQueue:基于数组的阻塞队列实现,在ArrayBlockingQueuee内部,维护了一个定长数组,以便缓存队列中的数据对象,其内部没有实现读写分离,意味着生产和消费不能完全并行,长度是需要定义的,可以指定先进先出或者先进后出,也叫有界队列,在很多场合非常适用。
ArrayBlockingQueue<String> array = new ArrayBlockingQueue<String>(5);
array.put("a");
array.put("b");
array.add("c");
array.add("d");
array.add("e");
array.add("f");
//System.out.println(array.offer("a", 3, TimeUnit.SECONDS));
LinkedBlockingQueue:基于链表的阻塞队列,和ArrayBlockingQueue类似,内部维护这一个链表的数据缓存队列。他可以高效的处理并发数据,是因为其内部实现了读写分离(读写分离两个锁),实现生产和消费并行。他是一个无界队列。
//阻塞队列
LinkedBlockingQueue<String> q = new LinkedBlockingQueue<String>();
q.offer("a");
q.offer("b");
q.offer("c");
q.offer("d");
q.offer("e");
q.add("f");
//System.out.println(q.size());
//for (Iterator iterator = q.iterator(); iterator.hasNext();) {
// String string = (String) iterator.next();
// System.out.println(string);
//}
List<String> list = new ArrayList<String>();
System.out.println(q.drainTo(list, 3));
System.out.println(list.size());
for (String string : list) {
System.out.println(string);
}
SynchronousQueue:一种没有缓冲的队列,生产的数据会被消费者直接获取并消费。初始化后无法加元素
final SynchronousQueue<String> q = new SynchronousQueue<String>();
Thread t1 = new Thread(new Runnable() {
@Override
public void run() {
try {
System.out.println(q.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
t1.start();
Thread t2 = new Thread(new Runnable() {
@Override
public void run() {
q.add("asdasd");
}
});
t2.start();
PriorityBlockingQueue:基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象决定,也就是说对象必须实现Comparabler接口),在实现PriorityBlockingQueue时,内部控制线程同步采用的是公屏锁,他也是一个无界的队列。
public class Task implements Comparable<Task>{
private int id ;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public int compareTo(Task task) {
return this.id > task.id ? 1 : (this.id < task.id ? -1 : 0);
}
public String toString(){
return this.id + "," + this.name;
}
}
PriorityBlockingQueue<Task> q = new PriorityBlockingQueue<Task>();
Task t1 = new Task();
t1.setId(3);
t1.setName("id为3");
Task t2 = new Task();
t2.setId(4);
t2.setName("id为4");
Task t3 = new Task();
t3.setId(1);
t3.setName("id为1");
//return this.id > task.id ? 1 : 0;
q.add(t1);//3
q.add(t2);//4
q.add(t3);//1
//for (Task task : q) {
// System.out.println(task.getId());
//}
// 1 3 4
System.out.println("容器:" + q);
System.out.println(q.take().getId());
System.out.println("容器:" + q);
System.out.println(q.take().getId());
System.out.println(q.take().getId());
DelayQueue:贷有延迟时间的Queue,队列中的元素只有当元素指定的时间到了,才能够从队列中取走该元素。DelayQueue中的对象必须实现Delayed接口,他是一个无界队列。应用于缓存数据超时的移除、任务超时处理、空闲连接的关闭。
//模拟网吧上网问题
public class Wangmin implements Delayed {
private String name;
//身份证
private String id;
//截止时间
private long endTime;
//定义时间工具类
private TimeUnit timeUnit = TimeUnit.SECONDS;
public Wangmin(String name,String id,long endTime){
this.name=name;
this.id=id;
this.endTime = endTime;
}
public String getName(){
return this.name;
}
public String getId(){
return this.id;
}
/**
* 用来判断是否到了截止时间
*/
@Override
public long getDelay(TimeUnit unit) {
//return unit.convert(endTime, TimeUnit.MILLISECONDS) - unit.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS);
return endTime - System.currentTimeMillis();
}
/**
* 相互批较排序用
*/
@Override
public int compareTo(Delayed delayed) {
Wangmin w = (Wangmin)delayed;
return this.getDelay(this.timeUnit) - w.getDelay(this.timeUnit) > 0 ? 1:0;
}
}
public class WangBa implements Runnable {
private DelayQueue<Wangmin> queue = new DelayQueue<Wangmin>();
public boolean yinye =true;
public void shangji(String name,String id,int money){
Wangmin man = new Wangmin(name, id, 1000 * money + System.currentTimeMillis());
System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"交钱"+money+"块,开始上机...");
this.queue.add(man);
}
public void xiaji(Wangmin man){
System.out.println("网名"+man.getName()+" 身份证"+man.getId()+"时间到下机...");
}
@Override
public void run() {
while(yinye){
try {
Wangmin man = queue.take();
xiaji(man);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public static void main(String args[]){
try{
System.out.println("网吧开始营业");
WangBa siyu = new WangBa();
Thread shangwang = new Thread(siyu);
shangwang.start();
siyu.shangji("路人甲", "123", 1);
siyu.shangji("路人乙", "234", 10);
siyu.shangji("路人丙", "345", 5);
}
catch(Exception e){
e.printStackTrace();
}
}
}
4、BlockingDeque:Java.util.concruuent包中的BlockingDeque接口是一种双端队列,向其中加入元素或从中取出元素都是线程安全的。一个线程生产元素并将元素插入到队列的两端。如果当前队列是满的,插入线程将会被阻塞直到一个移除元素的线程从队列中取出一个元素。同样,如果队列当前是空的,移除元素的线程会被阻塞直到一个插入元素的线程向队列中插入了一个元素。
BlockingDeque的方法
抛异常 | 特定值 | 阻塞 | 超时 | |
插入 | addFirst(o) | offerFirst(o) | putFirst(o) | offerFirst(o, timeout, timeunit) |
移除 | removeFirst(o) | pollFirst(o) | takeFirst(o) | pollFirst(timeout, timeunit) |
检查 | getFirst(o) | peekFirst(o) |
BlockingDeque继承自BlockingQueue:BlockingDeque接口继承自BlockingQueue接口。这意味着你可以把BlockingDeque作为BlockingQueue来使用。如果你这样做,那么各种插入元素的方法将会把元素增加到队列的尾部,并且将会从队列的头部开始移除元素。
下面的列表列出了BlockingQueue方法在BlockingDeque中的实现。
BlockingDeque | BlockingQueue |
add() | addLast() |
offer() x 2 | offerLast() x 2 |
put() | putLast() |
remove() | removeFirst() |
poll() x 2 | pollFirst() |
take() | takeFirst() |
element() | getFirst() |
peek() | peekFirst() |
LinkedBlockingDeque:由于BlockingDeque是一个接口类,使用时需要使用它的实现类。Java.util.concurrent包中有以下关于BlockingDeque接口的实现类:LinkedBlockingDeque。LinkedBlockingDeque是一个双端队列,如果一个线程试图从一个空的队列中取出元素,它将被阻塞住,不管线程是从哪一端去获取元素。
BlockingDeque<String> deque = new LinkedBlockingDeque<String>();
deque.addFirst("1");
deque.addLast("2");
String two = deque.takeLast();
String one = deque.takeFirst();