ConcurrentLinkedQueue的重要方法:
add()和offer()都是加入元素的方法(在ConcurrentLinkedQueue,这两个方法没有任何区别) poll()和peak()都是取头元素,区别在于前者会删除元素后者不会.ArrayBlockingQueue:
基于数组的阻塞队列实现,在ArrayBlockingQueue内部,维护了一个定长的数组,一遍缓存队列中的数据对象,对内部没实现读写分离,也就意味着生产和消费 不能完全并行,长度是需要定义的,可以指定现进先出,或者,后进后出,也叫有界队列,在很多场合非常实用,LinkenBlockingQueue:
基于链表的阻塞队列,同ArrayBlockingQueue类似,器内部也维护这一个数据缓存队列(该队列由一个链表构成),LinkedBlockingQueue之所以能够高效地 处理并发数据,是因为其内部实现采用分离锁(读写分离两个锁),从而实现生产者和消费者操作的完全并行运行.它是一个无界队列SynchronousQueue:
一种没有缓冲的队列,生产者产生的数据直接会被消费者获取并消费.看一个具体的例子:
SynchronousQueue<String> sQueue = new SynchronousQueue<String>(); sQueue.add("aaa");如果程序这样写,是肯定会报错的,因为SynchronousQueue里面是不能放元素的:
报的错: Exception in thread "main" java.lang.IllegalStateException: Queue full at java.util.AbstractQueue.add(AbstractQueue.java:98) at com.threadbasic015.SynchronousQueueDemo.main(SynchronousQueueDemo.java:8)但是并不是说SynchronousQueue不能使用add()方法;
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("aaa"); } }); t2.start(); 这端代码是没有问题的,一个线程从SyhchronsQueue拿元素,一个线程往SynchronousQueue队列里面放元素,但是需要注意的是,add()方法,放的元素并不是 放在这个SynchronousQueue队列里面,而是直接拿给了take()方法去获取,如果没有take()方法,那么add()方法肯定是有问题的.PriorityBlockingQueue:
基于优先级的阻塞队列(优先级的判断通过构造函数传入的Compator对象来决定,也就是说传入队列的对象必须实现Comparable接口),在实现 PriorityBlockingQueue时,内部控制线程同步的锁采用的是公平锁,他是一个无界的队列 这个队列是的元素是有优先级的,队列的元素要实现Comparaable接口,自定义比较的方法, 例子: 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) { System.out.println("this:" + this); System.out.println("task:" + task); System.out.println("==============="); return this.id > task.id ? 1 : (this.id < task.id ? -1 : 0); } @Override public String toString() { return "Task [id=" + id + ", name=" + name + "]"; } }take方法回去找优先级中最高的元素
> 元素放进队列,开始是没有顺序的,当调用队列的take()方法,取数据,那么队列里面的元素就进行了一次比较,注意里面没有进行排序,一调用take()方法,把优 先级最高的元素取出来
DelayQueue:
带有延迟时间的Queue,其中的元素只有当其指定的延迟时间到了,才能够从队列中获取元素.DelayQueue中元素必须实现Delayed接口,DelayQueue是一个 没有大小限制的队列,应用场景很多,比如对缓存超时的数据进行移除,任务超时处理,空闲连接的关闭等待.现在模拟一个例子:
网吧上网的例子,假设网吧开始营业,路人甲来上网交了1块钱,上了1小时,过了一段时间路人乙也来上网了,交了10块钱,上了10小时,过了一段时间路人丙来了, 交了5块钱,上了5小时.上网的时间跟交的钱成正比,这个事件相当于是队列中的延迟时间实现:定义一个网名类(WangMing)实现了Delayed接口这个类要放在DelayQueue队列里面:
public class WangMing implements Delayed { private String name; private String id; //身份证号 private Long endTime; // 截止时间 private TimeUnit timeUnit = TimeUnit.SECONDS; public WangMing(String name, String id, Long endTime) { this.name = name; this.id = id; this.endTime = endTime; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getId() { return id; } public void setId(String id) { this.id = id; } public Long getEndTime() { return endTime; } public void setEndTime(Long endTime) { this.endTime = endTime; } /** * 用来判断是到了延迟时间 * 返回值:剩余延迟时间;零或负值指示延迟时间已经用尽 */ @Override public long getDelay(TimeUnit unit) { System.out.println(this.getName() + " -当前时间:" + System.currentTimeMillis()); return endTime - System.currentTimeMillis(); } /** *相互比较,进行排序 */ @Override public int compareTo(Delayed delayed) { WangMing wangMing = (WangMing) delayed; return this.getDelay(timeUnit) - delayed.getDelay(timeUnit) > 0 ? 1:0; } }定义网吧(WangBa)类:
public class WangBa implements Runnable { private DelayQueue<WangMing> queue = new DelayQueue<WangMing>(); private boolean yingye = true; public void shangji(String name, String id, int money) { WangMing man = new WangMing(name, id, 1000*money + System.currentTimeMillis()); System.out.println("网民:" + name +"开始上机了 - " + man.getEndTime() +"后下机"); this.queue.add(man); } public void xiaxian(WangMing man) { System.out.println(man.getName() + "下线了"); } @Override public void run() { while(yingye) { try { WangMing wangMing = queue.take(); xiaxian(wangMing); } catch (Exception e) { e.printStackTrace(); } } } public static void main(String[] args) { try { WangBa wangBa = new WangBa(); System.out.println("网吧开始营业了"); Thread shangwang = new Thread(wangBa); shangwang.start(); wangBa.shangji("路人甲", "123", 2); wangBa.shangji("路人乙", "234", 5); wangBa.shangji("路人丙", "345", 3); } catch (Exception e) { e.printStackTrace(); } } }分析:
网吧类实现了Runnable接口,它的run方法,是要去DelaeyQuee队列中拿元素,如果,能够拿到元素,说明里面有元素的延迟时间已经用完了,就要下机.如果拿不到 元素,就一直在等着(这是一个死循环), WangMing实现了Delayed接口:有连个必须要实现的方法 1.getDelay()这个方法,只要这个元素没有超过延迟时间,就要一直运行这个方法,因为要通过这个方法来不断进行判断,是否过了延迟时间 2.comparedTo()这个方法,是DelayQueue内部元素需要实现排序要用的比较的方法> 打印结果: 网吧开始营业了 网民:路人甲开始上机了 - 1524627051663后下机 网民:路人乙开始上机了 - 1524627058664后下机 网民:路人丙开始上机了 - 1524627056664后下机 路人甲下线了 路人丙下线了 路人乙下线了
