`
standalone
  • 浏览: 611397 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

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

    博客分类:
  • java
阅读更多
今天不忙,学习一下java.util.concurrent.DelayQueue这个类的使用。参照了
http://www.concretepage.com/java/example_delayqueue_java.php
上的例子,但是这里有个坑。

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

http://www.blogjava.net/killme2008/archive/2010/10/22/335897.html
分享到:
评论

相关推荐

    DelayQueue延迟队列和Redis缓存实现订单自动取消功能

    在Java编程中,DelayQueue是一种特殊的并发队列,它遵循先进先出(FIFO)原则,但具有一个独特的特性:元素只有在其指定的延迟时间过去之后才能被获取和处理。这个特性使得DelayQueue成为实现定时任务和延迟操作的...

    Java多线程并发开发之DelayQueue使用示例

    DelayQueue是Java多线程并发开发中的一种常用的数据结构,它是一个无界的BlockingQueue,用于放置实现了Delayed接口的对象。DelayQueue的主要作用是按照对象的延迟时间来排序,以便在合适的时刻从队列中取出对象。 ...

    DelayQueue、Redis结合使延迟、定时任务使用源代码

    `DelayQueue`是Java并发库`java.util.concurrent`中的一个数据结构,它是一个基于优先级队列的无界阻塞队列,可以用于存储具有延迟时间的元素。而Redis则是一个高性能的键值数据库,通过其丰富的数据结构和操作,...

    DelayQueue的使用以及注意事项

    DelayQueue的使用以及注意事项,这里需要由BlockingQueue的基本知识,一般的Queue的使用方法poll(),take(),drainTo()和offer(),put()这些应该懂。

    DelayQueue

    学习视频,可以丰富java知识。能够获得更多的专业技能

    java利用delayedQueue实现本地的延迟队列

    为了使用 DelayQueue,我们需要首先声明一个 Delayed 的对象,例如,我们可以声明一个 Task 对象, Task 对象实现了 Delayed 接口,用于表示一个具有延迟执行的任务。 ``` public class Task&lt;T extends Runnable&gt; ...

    JDK自带的延迟队列-DelayQueue

    在Java的并发编程中,`DelayQueue`是一个非常特殊的队列,它属于并发包`java.util.concurrent`的一部分。`DelayQueue`是一个基于优先级队列(PriorityQueue)实现的无界阻塞队列,它的主要特性是元素只有在达到指定...

    springboot执行延时任务之DelayQueue的使用详解

    DelayQueue是一个无界阻塞队列,只有在延迟期满时,才能从中提取元素。它提供了在指定时间才能获取队列元素的功能,队列头元素是最接近过期的元素。DelayQueue的元素需要实现Delayed接口,该接口类定义如下: ...

    java实现一个小程序语句的延迟执行的小demo

    下面是一个简单的使用`ScheduledExecutorService`实现延迟执行的Java代码示例: ```java import java.util.concurrent.*; public class DelayExecutionDemo { public static void main(String[] args) { // 创建...

    Java并发编程相关源码集 包括多任务线程,线程池等.rar

     volatile关键字的非原子性、volatile关键字的使用、AtomicInteger原子性操作、线程安全小例子:多个线程竞争问题、多个线程多个锁问题、创建一个缓存的线程池、多线程使用Vector或者HashTable的示例(简单线程同步...

    java并发工具包 java.util.concurrent中文版用户指南pdf

    4. 延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque ...

    java.util.concurrent_您不知道的5件事

    当一个线程调用 `acquire()` 方法时,如果当前可用的许可数量大于0,则减少一个许可并让该线程继续执行;如果许可数量为0,则该线程被挂起,等待其他线程释放许可。 - **应用场景**:在需要限制对某个资源的并发...

    免费开源-【Java学习+面试指南】部分内容大部分是Java程序员所需要掌握的核心知识

    Unsafe 详细解Java SPI 机制详解Java语法糖详解集合知识点/面试题总结:Java集合常见知识点&面试题总结(上)(必看)Java集合常见知识点&面试题总结(下)(必看)Java容器使用注意事项总结源码分析:ArrayList核心...

    JAVA并发容器代码随读1

    例如,ArrayBlockingQueue 是一个有界的阻塞队列,它使用锁机制确保线程安全。然而,尽管 BlockingQueue 的基本操作是线程安全的,但像 `addAll`、`containsAll`、`retainAll` 和 `removeAll` 这样的批量操作并不...

    java concurrent 精简源码

    Java并发库是Java SE 5.0引入的一个重要特性,它提供了很多高级并发工具,如线程池、同步容器、并发集合以及阻塞队列等,极大地简化了并发编程。 2. **阻塞队列(BlockingQueue)** 阻塞队列是一种特殊的队列,当...

    java并发工具包 java.util.concurrent中文版pdf

    `BlockingQueue` 是 `java.util.concurrent` 包中的一个接口,它扩展了传统的 `Queue` 接口,并引入了阻塞特性。这意味着当队列为空时,从队列中移除元素的操作将会阻塞;同样地,当队列满时,向队列添加元素的操作...

    Java企业版中性能调节的最佳实践.pdf

    一个高效稳定的系统不仅能提高用户体验,还能降低运营成本,提升企业的竞争力。本文档旨在探讨Java企业版(Java EE)环境下性能调优的最佳实践,包括方法论、负载测试工具、软件栈中的各组件调优策略以及未来性能...

    基于SpringBoot的延迟消息Starter设计源码,支持DelayQueue、Redisson、RabbitMQ三种方式

    该项目是SpringBoot框架下的延迟...项目包含32个文件,涵盖24个Java源文件、4个XML配置文件、1个Git忽略文件、1个Markdown文件、1个YAML文件以及1个Spring Boot配置工厂文件,旨在简化延迟消息的实现和应用部署过程。

    Delayed interface and Delay Queue

    在"DelayQueueDemo.java"这个文件中,可能包含了一个示例程序,展示了如何创建一个Delayed对象并将其放入DelayQueue中。通常,这个示例会包含以下步骤: 1. 创建一个实现Delayed接口的类,例如`MyDelayedObject`,...

    Java并发工具包java.util.concurrent用户指南中英文对照阅读版.pdf

    延迟队列 DelayQueue 5. 链阻塞队列 LinkedBlockingQueue 6. 具有优先级的阻塞队列 PriorityBlockingQueue 7. 同步队列 SynchronousQueue 8. 阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque 10...

Global site tag (gtag.js) - Google Analytics