使用Java的DelayQueue容易碰到的一个坑

今天不忙,学习一下java.util.concurrent.DelayQueue这个类的使用。参照了
[url]http://www.concretepage.com/java/example_delayqueue_java.php[/url]
上的例子,但是这里有个坑。

先看一下整个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

那么会有什么问题呢?


Retrieves and removes the head of this queue, waiting if necessary until an element with an expired delay is available on this queue.
Returns:
the head of this queue
Throws:
java.lang.InterruptedException
181
182 public E take() throws InterruptedException {
183 final ReentrantLock lock = this.lock;
184 lock.lockInterruptibly();
185 try {
186 for (;;) {
187 E first = q.peek();
188 if (first == null) {
189 available.await();
190 } else {
191 long delay = first.getDelay(TimeUnit.NANOSECONDS);
192 if (delay > 0) {
193 long tl = available.awaitNanos(delay);
194 } else {
195 E x = q.poll();
196 assert x != null;
197 if (q.size() != 0)
198 available.signalAll(); // wake up other takers
199 return x;
200
201 }
202 }
203 }
204 } finally {
205 lock.unlock();
206 }
207 }



看一下DelayQueue的take()方法会发现,在队列首对象的delay>0的时候,等待的时间单位是nanos(193行),所以如果我刚才getDelay()里面没有将ms转换成ns,那么数值会小很多,line 193 会很快执行,再次循环进行判断,delay仍然大于0,注意,总的等待时间是固定的,现在是每次wait的时间片变小了,所以循环的次数多了,造成一个结果就是cpu占用上升!

如果打印出每次delay的值便可以看到用nanos多做了多少次循环,读者可以自己看一下,呵呵。

遇到这个坑的人我google到有:

[url]http://www.blogjava.net/killme2008/archive/2010/10/22/335897.html[/url]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值