先看一下整个code吧:
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
public class DelayQueueExample {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
DelayQueue<DelayedElement> dq=new DelayQueue<DelayedElement>();
long now = System.currentTimeMillis();
System.out.println("current time in ms:"+ now);
DelayedElement ob1=new DelayedElement("e1", now + 1000);
DelayedElement ob2=new DelayedElement("e2", now + 5000);
DelayedElement ob3=new DelayedElement("e3", now + 1500);
dq.add(ob1);
dq.add(ob2);
dq.add(ob3);
try {
Thread.sleep(1);
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
while(dq.size() > 0){
try {
DelayedElement e = dq.take();
System.out.println("current time in ms:"+ System.currentTimeMillis() +", element:"+ e.name);
} catch (InterruptedException e) {
throw new RuntimeException( e );
}
}
}
static class DelayedElement implements Delayed {
public long time;
public String name;
public DelayedElement(String name, long time){
this.name = name;
this.time = time;
}
@Override
public int compareTo(Delayed o) {
// TODO Auto-generated method stub
if(this.time < ((DelayedElement)o).time) return -1;
else if(this.time > ((DelayedElement)o).time)return 1;
else return 0;
}
@Override
public long getDelay(TimeUnit unit) {
// TODO Auto-generated method stub
long r = unit.convert(time - System.currentTimeMillis(), TimeUnit.NANOSECONDS);
//System.out.println("delay:"+ r);
return r;
}
}
}
注意getDelay(TimeUnit unit),这个是实现Delayed这个接口时候必须要实现的一个方法,容易遇坑的地方就是
long r = unit.convert(time - System.currentTimeMillis(), TimeUnit.NANOSECONDS);
这里应该使用的TimeUnit.MILLISECONDS而不是TimeUnit.NANOSECONDS,但是你会发现不管你用哪一个(或者其他的TimeUnit),这个程序的正确性是ok的,都会delay你所要的时间,例如分别使用这两种TimeUnit的输出: If using MILLISECONDS: current time in ms: 1369644922697 current time in ms: 1369644923697, element:e1 current time in ms: 1369644924197, element:e3 current time in ms: 1369644927697, element:e2 If using NANOSECONDS: current time in ms: 1369645748910 current time in ms: 1369645749910, element:e1 current time in ms: 1369645750410, element:e3 current time in ms: 1369645753910, element:e2 那么会有什么问题呢?
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(TimeUnit.NANOSECONDS);
if (delay > 0) {
long tl = available.awaitNanos(delay);
} else {
E x = q.poll();
assert x != null;
if (q.size() != 0)
available.signalAll(); // wake up other takers
return x;
}
}
}
} finally {
lock.unlock();
}
}
看一下DelayQueue的take()方法会发现,在队列首对象的delay>0的时候,等待的时间单位是nanos(193行),所以如果我刚才getDelay()里面没有将ms转换成ns,那么数值会小很多,line 193 会很快执行,再次循环进行判断,delay仍然大于0,注意,总的等待时间是固定的,现在是每次wait的时间片变小了,所以循环的次数多了,造成一个结果就是cpu占用上升! 如果打印出每次delay的值便可以看到用nanos多做了多少次循环,读者可以自己看一下