精巧好用的DelayQueue

我们谈一下实际的场景吧。我们在开发中,有如下场景

a) 关闭空闲连接。服务器中,有很多客户端的连接,空闲一段时间之后需要关闭之。
b) 缓存。缓存中的对象,超过了空闲时间,需要从缓存中移出。
c) 任务超时处理。在网络协议滑动窗口请求应答式交互时,处理超时未响应的请求。

一种笨笨的办法就是,使用一个后台线程,遍历所有对象,挨个检查。这种笨笨的办法简单好用,但是对象数量过多时,可能存在性能问题,检查间隔时间不好设置,间隔时间过大,影响精确度,多小则存在效率问题。而且做不到按超时的时间顺序处理。

这场景,使用DelayQueue最适合了。

DelayQueue是java.util.concurrent中提供的一个很有意思的类。很巧妙,非常棒!但是java doc和Java SE 5.0的source中都没有提供Sample。我最初在阅读ScheduledThreadPoolExecutor源码时,发现DelayQueue的妙用。随后在实际工作中,应用在session超时管理,网络应答通讯协议的请求超时处理。

本文将会对DelayQueue做一个介绍,然后列举应用场景。并且提供一个Delayed接口的实现和Sample代码。

DelayQueue是一个BlockingQueue,其特化的参数是Delayed。(不了解BlockingQueue的同学,先去了解BlockingQueue再看本文)
Delayed扩展了Comparable接口,比较的基准为延时的时间值,Delayed接口的实现类getDelay的返回值应为固定值(final)。DelayQueue内部是使用PriorityQueue实现的。

DelayQueue = BlockingQueue + PriorityQueue + Delayed

DelayQueue的关键元素BlockingQueue、PriorityQueue、Delayed。可以这么说,DelayQueue是一个使用优先队列(PriorityQueue)实现的BlockingQueue,优先队列的比较基准值是时间。

他们的基本定义如下

public interface Comparable<T> {
    public int compareTo(T o);
}
public interface Delayed extends Comparable<Delayed> {
    long getDelay(TimeUnit unit);
}
public class DelayQueue<E extends Delayed> implements BlockingQueue<E> {
    private final PriorityQueue<E> q = new PriorityQueue<E>();
}

转自:http://www.cnblogs.com/jobs/archive/2007/04/27/730255.html

模拟一个考试的日子,考试时间为120分钟,30分钟后才可交卷,当时间到了,或学生都交完卷了考试结束。

这个场景中几个点需要注意:

  1. 考试时间为120分钟,30分钟后才可交卷,初始化考生完成试卷时间最小应为30分钟
  2. 对于能够在120分钟内交卷的考生,如何实现这些考生交卷
  3. 对于120分钟内没有完成考试的考生,在120分钟考试时间到后需要让他们强制交卷
  4. 在所有的考生都交完卷后,需要将控制线程关闭

抽象出两个类,学生类和老师类,用DelayQueue存储考生(Student类)。每一个考生都有自己的名字和完成试卷的时间

Teacher线程对DelayQueue进行监控,收取完成试卷小于120分钟的学生的试卷。当考试时间120分钟到时,teacher线程宣布考试结束,强制DelayQueue中还存在的考生交卷。

package zhongqiu.common.base.thread;

import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class DelayQueueDemoOne {

    public static void main(String[] args) throws InterruptedException {
        // TODO Auto-generated method stub
        int studentNumber = 20;
        DelayQueue<Student> students = new DelayQueue<Student>();
        Random random = new Random();
        for (int i = 0; i < studentNumber; i++) {
            students.put(new Student("student" + (i + 1), 30 + random.nextInt(120)));
        }
        students.put(new Student("student",120));
        Thread teacherThread = new Thread(new Teacher(students));
        teacherThread.start();
    }
}

class Student implements Runnable, Delayed {

    private String name;
    public long workTime;
    private long submitTime;
    private boolean isForce = false;

    public Student() {
    }

    public Student(String name, long workTime) {
        this.name = name;
        this.workTime = workTime;
        this.submitTime = TimeUnit.NANOSECONDS.convert(workTime, TimeUnit.NANOSECONDS) + System.nanoTime();// 纳秒级别
    }

    @Override
    public int compareTo(Delayed o) {
        // TODO Auto-generated method stub
        if (o == null || !(o instanceof Student))
            return 1;
        if (o == this)
            return 0;
        Student s = (Student) o;
        if (this.workTime > s.workTime) {
            return 1;
        } else if (this.workTime == s.workTime) {
            return 0;
        } else {
            return -1;
        }
    }

    @Override
    public long getDelay(TimeUnit unit) {
        // TODO Auto-generated method stub
        return unit.convert(submitTime - System.nanoTime(), TimeUnit.NANOSECONDS);
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        if (isForce) {
            System.out.println(name + " 交卷,实际用时 120分钟");
        } else {
            System.out.println(name + " 交卷," + "实际用时 " + workTime + " 分钟");
        }
    }

    public boolean isForce() {
        return isForce;
    }

    public void setForce(boolean isForce) {
        this.isForce = isForce;
    }

}

class Teacher implements Runnable {
    private int counter = 20;
    private DelayQueue<Student> students;

    public Teacher(DelayQueue<Student> students) {
        this.students = students;
    }

    @Override
    public void run() {
        // TODO Auto-generated method stub
        try {
            System.out.println(" test start");
            while (counter > 0) {
                Student student = students.poll();
                if (student.workTime<120) {
                    student.run();
                    if (counter > 0) {
                        counter--;
                    }
                } else {
                    System.out.println(" 考试时间到,全部交卷!");
                    Student tmpStudent;
                    for (Iterator<Student> iterator2 = students.iterator(); iterator2.hasNext();) {
                        tmpStudent = iterator2.next();
                        tmpStudent.setForce(true);
                        tmpStudent.run();
                        if (counter > 0) {
                            counter--;
                        }
                    }
                }
            }
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

}

  

时间: 2024-07-31 21:29:15

精巧好用的DelayQueue的相关文章

20150817---成长日记1---DelayQueue&amp;&amp;Delayed&amp;&amp;Other

今天第一次接触DelayQueue,源于项目中的话单解析入库的拆分线程中引入,首先简单了解一下DelayQueue: DelayQueue是一个无界阻塞队列,只有在延迟期满时才能从中提取元素.该队列的头部是延迟期满后保存时间最长的Delayed 元素. 问题1:如何来判断延迟期是否满了呢?   ----后面解答,下面继续. DelayQueue阻塞队列在我们系统开发中也常常会用到,例如:缓存系统的设计,缓存中的对象,超过了空闲时间,需要从缓存中移出:任务调度系统,能够准确的把握任务的执行时间.我

DelayQueue应用场景,多考生考试

该场景来自于:http://www.cnblogs.com/sunzhenchao/p/3515085.html. 模拟一个考试的日子,考试时间为120分钟,30分钟后才可交卷,当时间到了,或学生都交完卷了考试结束. 这个场景中几个点需要注意: 考试时间为120分钟,30分钟后才可交卷,初始化考生完成试卷时间最小应为30分钟 对于能够在120分钟内交卷的考生,如何实现这些考生交卷 对于120分钟内没有完成考试的考生,在120分钟考试时间到后需要让他们强制交卷 在所有的考生都交完卷后,需要将控制线

java.util.concurrent.DelayQueue 源码学习

jdk1.8 DelayQueue,带有延迟元素的线程安全队列,当非阻塞从队列中获取元素时,返回最早达到延迟时间的元素,或空(没有元素达到延迟时间).DelayQueue的泛型参数需要实现Delayed接口,Delayed接口继承了Comparable接口,其内部使用非线程安全的优先队列(PriorityQueue),并使用Leader/Followers模式,最小化不必要的等待时间.DelayQueue不允许包含null元素. Leader/Followers模式,借用其他博客的话来解释下:

DelayQueue

DelayQueue是一个无界队列,只有在延迟期满的时候,才可以取出元素.该队列的头部存储的延期期满了后保存时间最长的元素. DelayQueue阻塞队列在我们系统开发中也常常会用到,例如:缓存系统的设计,缓存中的对象,超过了空闲时间,需要从缓存中移出:任务调度系统,能够准确把握任务的执行时间.我们可能需要通过线程处理很多时间上要求很严格的数据,如果使用普通的线程,我们就需要遍历所有的对象,一个一个的检 查看数据是否过期等,首先这样在执行上的效率不会太高,其次就是这种设计的风格也大大的影响了数据

java DelayQueue 延期队列 21.7.3 -------thinking java 4

package org.rui.thread.newc; import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.ExecutorService; import java.util.concur

Java并发新构件之DelayQueue

DelayQueue主要用于放置实现了Delay接口的对象,其中的对象只能在其时刻到期时才能从队列中取走.这种队列是有序的,即对头的延迟到期时间最短.如果没有任何延迟到期,那么久不会有任何头元素,并且poll()将返回null(正因为这样,你不能将null放置到这种队列中) 下面是一个示例,其中的Delayed对象自身就是人物,而DelayedTaskConsumer将最"紧急"的任务从队列中取出来,然后运行它: import java.util.ArrayList; import j

.NET独有的精巧泛型设计模式

在.NET发展史中,2.0是具有里程碑意义的一个版本.从这个版本,.NET青出于蓝(Java),而胜于蓝.在.NET 2.0带来的诸多新特性中,我认为泛型是最重要,没有之一. 虽然泛型出现已有多年,连Java都早已借鉴引入了泛型(虽然是语法糖),可是用泛型的编程思维方式并没有得到相应的普及.一方面是由于过去大量的Framework仍然是在非泛型时代写成的,另一方面泛型的设计模式没有得到发展,改变的时候该到了. 来举一个例子说明这两点.我们如果写过网络数据抓取的代码,应该熟悉这样的代码: var

Java之DelayQueue实际应用

在学习Java 多线程并发开发过程中,了解到DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其 中的对象只能在其到期时才能从队列中取走.这种队列是有序的,即队头对象的延迟到期时间最长.注意:不能将null元素放置到这种队列中. Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象.此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序. 在网上也看到两

java并发之DelayQueue实际运用示例

在学习Java 多线程并发开发过程中,了解到DelayQueue类的主要作用:是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象,其中的对象只能在其到期时才能从队列中取走.这种队列是有序的,即队头对象的延迟到期时间最长.注意:不能将null元素放置到这种队列中. Delayed,一种混合风格的接口,用来标记那些应该在给定延迟时间之后执行的对象.此接口的实现必须定义一个 compareTo 方法,该方法提供与此接口的 getDelay 方法一致的排序. 在网上也看到两个