该场景来自 模拟一个考试的日子,考试时间为120分钟,30分钟后才可交卷,当时间到了,或学生都交完卷了考试结束。
这个场景中几个点需要注意:
实现思想:用DelayQueue存储考生(Student类),每一个考生都有自己的名字和完成试卷的时间,Teacher线程对DelayQueue进行监控,收取完成试卷小于120分钟的学生的试卷。当考试时间120分钟到时,先关闭Teacher线程,然后强制DelayQueue中还存在的考生交卷。每一个考生交卷都会进行一次countDownLatch.countDown(),当countDownLatch.await()不再阻塞说明所有考生都交完卷了,而后结束考试。
package com.my.base.concurrent.delayQueue;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class Exam {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
int studentNumber = 20;
CountDownLatch countDownLatch = new CountDownLatch(studentNumber+1);
DelayQueue< Student> students = new DelayQueue
Random random = new Random();
for (int i = 0; i < studentNumber; i++) {
students.put(new Student("student"+(i+1), 30+random.nextInt(120),countDownLatch));
}
Thread teacherThread =new Thread(new Teacher(students));
students.put(new EndExam(students, 120,countDownLatch,teacherThread));
teacherThread.start();
countDownLatch.await();
System.out.println(" 考试时间到,全部交卷!");
}
}
class Student implements Runnable,Delayed{
private String name;
private long workTime;
private long submitTime;
private boolean isForce = false;
private CountDownLatch countDownLatch;
public Student(){}
public Student(String name,long workTime,CountDownLatch countDownLatch){
this.name = name;
this.workTime = workTime;
this.submitTime = TimeUnit.NANOSECONDS.convert(workTime, TimeUnit.NANOSECONDS)+System.nanoTime();
this.countDownLatch = countDownLatch;
}
@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 + " 交卷, 希望用时" + workTime + "分钟"+" ,实际用时 120分钟" );
}else {
System.out.println(name + " 交卷, 希望用时" + workTime + "分钟"+" ,实际用时 "+workTime +" 分钟");
}
countDownLatch.countDown();
}
public boolean isForce() {
return isForce;
}
public void setForce(boolean isForce) {
this.isForce = isForce;
}
}
class EndExam extends Student{
private DelayQueue
private CountDownLatch countDownLatch;
private Thread teacherThread;
public EndExam(DelayQueue
super("强制收卷", workTime,countDownLatch);
this.students = students;
this.countDownLatch = countDownLatch;
this.teacherThread = teacherThread;
}
@Override
public void run() {
// TODO Auto-generated method stub
teacherThread.interrupt();
Student tmpStudent;
for (Iterator
tmpStudent = iterator2.next();
tmpStudent.setForce(true);
tmpStudent.run();
}
countDownLatch.countDown();
}
}
class Teacher implements Runnable{
private DelayQueue
public Teacher(DelayQueue
this.students = students;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
System.out.println(" test start");
while(!Thread.interrupted()){
students.take().run();
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
该场景来自于http://www.cnblogs.com/jobs/archive/2007/04/27/730255.html,向缓存添加内容时,给每一个key设定过期时间,系统自动将超过过期时间的key清除。
这个场景中几个点需要注意:
A:当向缓存中添加key-value对时,如果这个key在缓存中存在并且还没有过期,需要用这个key对应的新过期时间
B:为了能够让DelayQueue将其已保存的key删除,需要重写实现Delayed接口添加到DelayQueue的DelayedItem的hashCode函数和equals函数
C:当缓存关闭,监控程序也应关闭,因而监控线程应当用守护线程
package com.my.base.concurrent.delayQueue;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
/**
*Cache.java
*
*
*/
public class Cache
public ConcurrentHashMap
public DelayQueue
public void put(K k,V v,long liveTime){
V v2 = map.put(k, v);
DelayedItem
if (v2 != null) {
queue.remove(tmpItem);
}
queue.put(tmpItem);
}
public Cache(){
Thread t = new Thread(){
@Override
public void run(){
dameonCheckOverdueKey();
}
};
t.setDaemon(true);
t.start();
}
public void dameonCheckOverdueKey(){
while (true) {
DelayedItem
if (delayedItem != null) {
map.remove(delayedItem.getT());
System.out.println(System.nanoTime()+" remove "+delayedItem.getT() +" from cache");
}
try {
Thread.sleep(300);
} catch (Exception e) {
// TODO: handle exception
}
}
}
public static void main(String[] args) throws InterruptedException {
Random random = new Random();
int cacheNumber = 10;
int liveTime = 0;
Cache
for (int i = 0; i < cacheNumber; i++) {
liveTime = random.nextInt(3000);
System.out.println(i+" "+liveTime);
cache.put(i+"", i, random.nextInt(liveTime));
if (random.nextInt(cacheNumber) > 7) {
liveTime = random.nextInt(3000);
System.out.println(i+" "+liveTime);
cache.put(i+"", i, random.nextInt(liveTime));
}
}
Thread.sleep(3000);
System.out.println();
}
}
class DelayedItem
private T t;
private long liveTime ;
private long removeTime;
public DelayedItem(T t,long liveTime){
this.setT(t);
this.liveTime = liveTime;
this.removeTime = TimeUnit.NANOSECONDS.convert(liveTime, TimeUnit.NANOSECONDS) + System.nanoTime();
}
@Override
public int compareTo(Delayed o) {
if (o == null) return 1;
if (o == this) return 0;
if (o instanceof DelayedItem){
DelayedItem
if (liveTime > tmpDelayedItem.liveTime ) {
return 1;
}else if (liveTime == tmpDelayedItem.liveTime) {
return 0;
}else {
return -1;
}
}
long diff = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
return diff > 0 ? 1:diff == 0? 0:-1;
}
@Override
public long getDelay(TimeUnit unit) {
return unit.convert(removeTime - System.nanoTime(), unit);
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
@Override
public int hashCode(){
return t.hashCode();
}
@Override
public boolean equals(Object object){
if (object instanceof DelayedItem) {
return object.hashCode() == hashCode() ?true:false;
}
return false;
}
}
如上实现也可使用redis 托管实现,过期失效key的自动删除。