在併發隊列上,JDK提供了兩種實現,一個是以ConcurrentLinkQueue爲代表的高性能的隊列,一個是以BlockingQueue接口爲代表的阻塞隊列,無論哪種都繼承自Queue
一、ConcurrentLinkedQueue
ConcurrentLinkedQueue:是一個適用於高併發場景下的隊列,通過無鎖的方式,實現了高併發狀態下的高性能,通常ConcurrentLinkedQueue性能好於BlockingQueue,它是一個基於鏈接節點的無界線程安全隊列。該隊列的元素遵循先進先出的原則,該隊列不允許null元素。
ConcurrentLinkedQueue重要方法:
()和offer()都是加入元素的方法,(ConcurrentLinkedQueue中,這兩個元素沒有任何的區別)
pull()和peek()都是取頭元素節點,區別在於前者會刪除元素,後者不會
二、BlockingQueue接口
1、ArrayBlockingQueue:基於數組的阻塞隊列實現,在ArrayBlockingQueue內部,維護了一個定長數組,以便緩存對列中的數據對象,其內部沒有實現讀寫分離,意味着生產和消費不能完全並行,長度是需要定義的,可以指定先進先出或者先進後出,也叫做有界隊列,很多場景都適合使用。
2、LinkBlockingQueue:基於鏈表的阻塞隊列,同ArrayBlockingQueue類似,其內部維持着一個數據緩衝隊列(該隊列由一個鏈表組成),LinkBlockingQueue之所以能夠高效的處理併發數據,是因爲其內部實現採用分離鎖(讀寫分離兩個鎖),從而實現生產者和消費者操作的完全並行運行。是一個無界隊列。
3、PriorityBlockingQueue:基於優先級的阻塞隊列(優先級的判斷通過構造函數傳入的Compator對象決定,也就是說傳入隊列的對象必須實現Comparable接口),在實現PriorityBlockingQueue時,內部控制線程同步的鎖採用的公平鎖,是一個無界隊列
4、DelayQueue:帶有延遲時間的Queue,其中的元素只有當其指定的延遲時間到了,才能夠從隊列中獲取到該元素。DelayQueue中的元素必須實現Delayed接口,DelayQueue是一個沒有限制大小的隊列,應用場景很多,比如對緩存超時的數據進行移除、任務超時處理,空閒連接的關閉等等
5、SynchronousQueue:一種沒有緩衝的隊列,生產者產生的數據直接會被消費者獲取並且消費
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;
}
}
public class UsePriorityBlockingQueue {
public static void main(String[] args) throws Exception{
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
// 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代碼示例:
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();
}
}
}