/**
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.activemq.thread;

import java.util.HashMap;

import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

/**
 * @version $Revision$
 */
public final class Scheduler {

    public static final ScheduledThreadPoolExecutor CLOCK_DAEMON = new ScheduledThreadPoolExecutor(5, createThreadFactory());
    static {
        CLOCK_DAEMON.setKeepAliveTime(5, TimeUnit.SECONDS);
    }
    private static final HashMap<Runnable, ScheduledFuture> CLOCK_TICKETS = new HashMap<Runnable, ScheduledFuture>();

    private Scheduler() {
    }

    private static ThreadFactory createThreadFactory() {
        return new ThreadFactory() {
            public Thread newThread(Runnable runnable) {
                Thread thread = new Thread(runnable, "ActiveMQ Scheduler");
                thread.setDaemon(true);
                return thread;
            }
        };
    }

    public static synchronized void executePeriodically(final Runnable task, long period) {
        ScheduledFuture ticket = CLOCK_DAEMON
            .scheduleAtFixedRate(task, period, period, TimeUnit.MILLISECONDS);
        CLOCK_TICKETS.put(task, ticket);
    }

    public static synchronized void cancel(Runnable task) {
        ScheduledFuture ticket = CLOCK_TICKETS.remove(task);
        if (ticket != null) {
            ticket.cancel(false);
            if (ticket instanceof Runnable) {
                CLOCK_DAEMON.remove((Runnable)ticket);
            }
        }
    }

    public static void executeAfterDelay(final Runnable task, long redeliveryDelay) {
        CLOCK_DAEMON.schedule(task, redeliveryDelay, TimeUnit.MILLISECONDS);
    }

}

@@ -860,17 +860,16 @@
 ashMap;%0A
-%0A
 import j
@@ -881,172 +881,41 @@
 til.
-concurrent.ScheduledFuture;%0Aimport java.util.concurrent.ScheduledThreadPoolExecutor;%0Aimport java.util.concurrent.ThreadFactory;%0Aimport java.util.concurrent.TimeUnit
+Timer;%0Aimport java.util.TimerTask
 ;%0A%0A/
@@ -977,29 +977,30 @@
 ler %7B%0A%0A    p
-ublic
+rivate
  static fina
@@ -1001,24 +1001,30 @@
 c final 
+class 
 Schedule
 dThreadP
@@ -1019,181 +1019,276 @@
 dule
-dThreadPoolExecutor CLOCK_DAEMON = new ScheduledThreadPoolExecutor(5, createThreadFactory());%0A    static %7B%0A        CLOCK_DAEMON.setKeepAliveTime(5, TimeUnit.SECONDS
+rTimerTask extends TimerTask %7B%0A%09%09private final Runnable task;%0A%0A%09%09private SchedulerTimerTask(Runnable task) %7B%0A%09%09%09this.task = task;%0A%09%09%7D%0A%0A%09%09public void run() %7B%0A%09%09%09task.run();%09%09%09%09%09%09%09%0A%09%09%7D%0A%09%7D%0A%0A%09public static final Timer CLOCK_DAEMON = new Timer(%22ActiveMQ Scheduler%22, true
 );%0A
-    %7D%0A
     
@@ -1330,37 +1330,29 @@
 le, 
-ScheduledFuture%3E CLOCK_TICKET
+TimerTask%3E TIMER_TASK
 S = 
@@ -1373,31 +1373,25 @@
 nnable, 
-ScheduledFuture
+TimerTask
 %3E();%0A%0A  
@@ -1425,338 +1425,8 @@
  %7D%0A%0A
-    private static ThreadFactory createThreadFactory() %7B%0A        return new ThreadFactory() %7B%0A            public Thread newThread(Runnable runnable) %7B%0A                Thread thread = new Thread(runnable, %22ActiveMQ Scheduler%22);%0A                thread.setDaemon(true);%0A                return thread;%0A            %7D%0A        %7D;%0A    %7D%0A%0A
     
@@ -1521,62 +1521,81 @@
     
-    ScheduledFuture ticket = CLOCK_DAEMON%0A            
+%09TimerTask timerTask = new SchedulerTimerTask(task);%0A        CLOCK_DAEMON
 .sch
@@ -1612,16 +1612,21 @@
 edRate(t
+imerT
 ask, per
@@ -1640,54 +1640,29 @@
 riod
-, TimeUnit.MILLISECONDS);%0A        CLOCK_TICKET
+);%0A        TIMER_TASK
 S.pu
@@ -1671,20 +1671,23 @@
 task, ti
-cket
+merTask
 );%0A    %7D
@@ -1756,49 +1756,38 @@
     
-    ScheduledFuture ticket = CLOCK_TICKET
+%09TimerTask ticket = TIMER_TASK
 S.re
@@ -1858,131 +1858,11 @@
 cel(
-false
 );%0A
-            if (ticket instanceof Runnable) %7B%0A                CLOCK_DAEMON.remove((Runnable)ticket);%0A            %7D%0A
     
@@ -1956,24 +1956,81 @@
 eryDelay) %7B%0A
+    %09TimerTask timerTask = new SchedulerTimerTask(task);%0A
         CLOC
@@ -2048,16 +2048,21 @@
 hedule(t
+imerT
 ask, red
@@ -2077,31 +2077,8 @@
 elay
-, TimeUnit.MILLISECONDS
 );%0A 

Switch to using a Timer to schedual tasks. Seems to have much more acurate time delays between executions.