DelayQueue 学习和应用
来源:互联网 发布:淘宝ysl口红真假 编辑:程序博客网 时间:2024/05/20 07:32
DelayQueue的实现原理
DelayQueue的本质是一个实现了针对元素为Delayed的PriorityQueue, 它里面比较出彩的地方就是使用了Leader/Follower 模式,来减少线程为是否过期轮询,这样提高了系统效率。
public interface Delayed extends Comparable<Delayed> { /** * Returns the remaining delay associated with this object, in the * given time unit. * * @param unit the time unit * @return the remaining delay; zero or negative values indicate * that the delay has already elapsed */ long getDelay(TimeUnit unit);}
主要代码剖析:
public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> { private final transient ReentrantLock lock = new ReentrantLock(); private final PriorityQueue<E> q = new PriorityQueue<E>(); /** * Thread designated to wait for the element at the head of * the queue. This variant of the Leader-Follower pattern * (http://www.cs.wustl.edu/~schmidt/POSA/POSA2/) serves to * minimize unnecessary timed waiting. When a thread becomes * the leader, it waits only for the next delay to elapse, but * other threads await indefinitely. The leader thread must * signal some other thread before returning from take() or * poll(...), unless some other thread becomes leader in the * interim. Whenever the head of the queue is replaced with * an element with an earlier expiration time, the leader * field is invalidated by being reset to null, and some * waiting thread, but not necessarily the current leader, is * signalled. So waiting threads must be prepared to acquire * and lose leadership while waiting. */ private Thread leader = null;
上面代码指出了内部实现,一个优先级队列,一个并发锁,还有个LEADER/FOLLOWER的head;
Leader/Follower 模式 参看 http://www.cs.wustl.edu/~schmidt/POSA/POSA2/
offer 方法:
public boolean offer(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { q.offer(e); if (q.peek() == e) { leader = null; available.signal(); } return true; } finally { lock.unlock(); } }
take 方法:
public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { E first = q.peek(); if (first == null) available.await(); else { long delay = first.getDelay(NANOSECONDS); if (delay <= 0) return q.poll(); first = null; // don't retain ref while waiting if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); } finally { if (leader == thisThread) leader = null; } } } } } finally { if (leader == null && q.peek() != null) available.signal(); lock.unlock(); } }
最重要的是这里:
first = null; // don't retain ref while waiting if (leader != null) available.await(); else { Thread thisThread = Thread.currentThread(); leader = thisThread; try { available.awaitNanos(delay); } finally { if (leader == thisThread) leader = null; } }
为什么不是直接
available.awaitNanos(delay);每个awaitNanos 就像给每个线程挂一个倒计时闹钟一样,要是直接用这个方式的话,那么每个需要等待的线程就需要挂一个倒计时的闹钟,这样的话,效率就变低了很多。
所以能理解这里为什么使用leader / follower 模式提高效率了。
DelayQueue的常用方法
public void put(E e) public E take() throws InterruptedException public boolean offer(E e) public E poll()public int drainTo(Collection<? super E> c)
DelayQueue的应用案例
该场景来自于http://ideasforjava.iteye.com/blog/657384,模拟一个考试的日子,考试时间为120分钟,30分钟后才可交卷,当时间到了,或学生都交完卷了考试结束。
这个场景中几个点需要注意:
- 考试时间为120分钟,30分钟后才可交卷,初始化考生完成试卷时间最小应为30分钟
- 对于能够在120分钟内交卷的考生,如何实现这些考生交卷
- 对于120分钟内没有完成考试的考生,在120分钟考试时间到后需要让他们强制交卷
package test.time;import java.util.concurrent.Delayed;import java.util.concurrent.TimeUnit;public class Examinee implements Delayed {private int id;private String name;private long submitTime;public Examinee(int i){this.id = i;this.name = "考生-" + i;this.submitTime = Exam.EXAM_DEADLINE;}public int getId(){return id;}/** * 交卷了哦。 */public void submit(){long current = System.currentTimeMillis();if(current >= Exam.EXAM_MIN_TIME){submitTime = current;}else{long cost = TimeUnit.SECONDS.convert(current - Exam.EXAM_START, TimeUnit.MILLISECONDS);System.err.println("考试时间没有超过30分钟, ["+name+"] 不能交卷, 考试用时: "+cost);}}@Overridepublic int compareTo(Delayed o) {return (int)(getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));}@Overridepublic long getDelay(TimeUnit unit) {long delayMills = submitTime - System.currentTimeMillis();return unit.convert(delayMills, TimeUnit.MILLISECONDS);}public String toString(){long current = System.currentTimeMillis();long cost = TimeUnit.SECONDS.convert(current - Exam.EXAM_START, TimeUnit.MILLISECONDS);return name+" 在已经提交试卷, 考试耗时: "+cost;}}
package test.time;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import java.util.LinkedList;import java.util.List;import java.util.Map;import java.util.Random;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.DelayQueue;import java.util.concurrent.TimeUnit;public class Exam {// 考试开始时间static long EXAM_START = System.currentTimeMillis();// 考试时间 120 秒 (为了方便模拟)static long EXAM_DEADLINE = EXAM_START + 120*1000L;// 最早交卷时间 30 秒static long EXAM_MIN_TIME = EXAM_START + 30*1000L;// 考场总人数private static final int EXAMINEE_NUM = 20;private DelayQueue<Examinee> examinees = new DelayQueue<>();private Map<Integer, Examinee> map = new ConcurrentHashMap<>(EXAMINEE_NUM*3/2);private int submitCount;public Exam(){for(int i=1; i<=EXAMINEE_NUM; i++){Examinee e = new Examinee(i);examinees.offer(e);map.put(i, e);}}public void examining() throws InterruptedException{DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");Date start = new Date(EXAM_START);Date end = new Date(EXAM_DEADLINE);System.out.println("====> 考试开始 ["+format.format(start)+"] ...");// 25 分钟以后TimeUnit.SECONDS.sleep(25);while(System.currentTimeMillis() <= EXAM_DEADLINE ){someoneSubmit();TimeUnit.SECONDS.sleep(2);System.out.println("--------------- time past 2 seconds -------");List<Examinee> submitted = new LinkedList<>();examinees.drainTo(submitted);for(Examinee e: submitted){System.out.println(e);}submitCount += submitted.size();if(submitCount >= EXAMINEE_NUM){break;}}System.out.println("====> 考试结束 ["+format.format(end)+"] ...");}void someoneSubmit(){int num = new Random().nextInt(EXAMINEE_NUM)+1;map.get(num).submit();}public static void main(String[] args){try {new Exam().examining();} catch (InterruptedException e) {e.printStackTrace();}}}
0 0
- DelayQueue 学习和应用
- BlockingQueue和DelayQueue学习
- DelayQueue 学习
- DelayQueue 实际应用
- DelayQueue应用举例
- Thinking in Java学习笔记 DelayQueue和Delayed接口
- DelayQueue
- DelayQueue
- DelayQueue
- DelayQueue
- DelayQueue
- DelayQueue
- DelayQueue
- DelayQueue
- delayqueue
- DelayQueue
- DelayQueue模拟TImer和scheduler
- J.U.C-DelayQueue原理与应用
- 并发编程---Java并发容器原理原理剖析(一)ConcurrentHashMap
- HDU4777 Rabbit Kingdom(树状数组)
- clone和clone(true)的差别
- Servlet Filter
- AFHTTPRequestOperationManager在引入afnetworking后依然找不到
- DelayQueue 学习和应用
- Android Studio "佛祖保佑 永无bug" 注释模板设置详解(仅供娱乐)
- gcc/g++
- table前端分页
- 一种基于自定义控件的验证码
- python正则表达式简单使用
- HBase-----数据模型。定位一条数据4个标签(TableName, RowKey, ColumnKey, Timestamp)
- 夹杂数字字母大小写的字符串排序方法
- JavaScript substr() 方法实例