All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jgroups.util.TimeScheduler3 Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 33.0.2.Final
Show newest version

package org.jgroups.util;


import org.jgroups.Global;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;

import java.util.List;
import java.util.concurrent.*;


/**
 * Implementation of {@link TimeScheduler}. Based on the {@link TimeScheduler2} implementation
 * with various fixes and enhancements. Uses a {@link DelayQueue} to order tasks according to execution times
 * @author Bela Ban
 * @since  3.3
 */
public class TimeScheduler3 implements TimeScheduler, Runnable {
    /** Thread pool used to execute the tasks */
    protected final ThreadPoolExecutor                pool;

    /** DelayQueue with tasks being sorted according to execution times (next execution first) */
    protected final BlockingQueue               queue=new DelayQueue<>();

    /** Thread which removes tasks ready to be executed from the queue and submits them to the pool for execution */
    protected volatile Thread                         runner;

    protected static final Log                        log=LogFactory.getLog(TimeScheduler3.class);

    protected ThreadFactory                           timer_thread_factory=null;

    protected static enum TaskType                    {dynamic, fixed_rate, fixed_delay}


    /**
     * Create a scheduler that executes tasks in dynamically adjustable intervals
     */
    public TimeScheduler3() {
        pool=new ThreadPoolExecutor(4, 10,
                                    5000, TimeUnit.MILLISECONDS, new LinkedBlockingQueue(5000),
                                    Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());
        start();
    }


    public TimeScheduler3(ThreadFactory factory, int min_threads, int max_threads, long keep_alive_time, int max_queue_size,
                          String rejection_policy) {
        timer_thread_factory=factory;
        pool=new ThreadPoolExecutor(min_threads, max_threads,keep_alive_time, TimeUnit.MILLISECONDS,
                                    new LinkedBlockingQueue(max_queue_size),
                                    factory, Util.parseRejectionPolicy(rejection_policy));
        start();
    }



    public void    setThreadFactory(ThreadFactory f) {pool.setThreadFactory(f);}
    public int     getMinThreads()                   {return pool.getCorePoolSize();}
    public void    setMinThreads(int size)           {pool.setCorePoolSize(size);}
    public int     getMaxThreads()                   {return pool.getMaximumPoolSize();}
    public void    setMaxThreads(int size)           {pool.setMaximumPoolSize(size);}
    public long    getKeepAliveTime()                {return pool.getKeepAliveTime(TimeUnit.MILLISECONDS);}
    public void    setKeepAliveTime(long time)       {pool.setKeepAliveTime(time, TimeUnit.MILLISECONDS);}
    public int     getCurrentThreads()               {return pool.getPoolSize();}
    public int     getQueueSize()                    {return pool.getQueue().size();}
    public int     size()                            {return queue.size();}
    public String  toString()                        {return getClass().getSimpleName();}
    public boolean isShutdown()                      {return pool.isShutdown();}


    public String dumpTimerTasks() {
        StringBuilder sb=new StringBuilder();
        for(Task task: queue) {
            sb.append(task);
            if(task.isCancelled())
                sb.append(" (cancelled)");
            sb.append("\n");
        }
        return sb.toString();
    }



    public void execute(Runnable task) {
        submitToPool(task instanceof TimeScheduler.Task?
                       new RecurringTask(task, TaskType.dynamic, 0, ((TimeScheduler.Task)task).nextInterval(), TimeUnit.MILLISECONDS)
                       : new Task(task)); // we'll execute the task directly
    }


    public Future schedule(Runnable work, long initial_delay, TimeUnit unit) {
        return doSchedule(new Task(work, initial_delay, unit), initial_delay);
    }



    public Future scheduleWithFixedDelay(Runnable work, long initial_delay, long delay, TimeUnit unit) {
        return scheduleRecurring(work, TaskType.fixed_delay, initial_delay, delay, unit);
    }


    public Future scheduleAtFixedRate(Runnable work, long initial_delay, long delay, TimeUnit unit) {
        return scheduleRecurring(work,TaskType.fixed_rate,initial_delay,delay,unit);
    }


    /**
     * Schedule a task for execution at varying intervals. After execution, the task will get rescheduled after
     * {@link org.jgroups.util.TimeScheduler.Task#nextInterval()} milliseconds. The task is never done until
     * nextInterval() returns a value <= 0 or the task is cancelled.

* Note that the task is rescheduled relative to the last time is actually executed. This is similar to * {@link #scheduleWithFixedDelay(Runnable,long,long,java.util.concurrent.TimeUnit)}. * @param work the task to execute */ public Future scheduleWithDynamicInterval(TimeScheduler.Task work) { return scheduleRecurring(work, TaskType.dynamic, work.nextInterval(), 0, TimeUnit.MILLISECONDS); } protected void start() { startRunner(); } /** * Stops the timer, cancelling all tasks */ public void stop() { stopRunner(); // we may need to do multiple iterations as the iterator works on a copy and tasks might have been added just // after the iterator() call returned while(!queue.isEmpty()) for(Task entry: queue) { entry.cancel(true); queue.remove(entry); } queue.clear(); List remaining_tasks=pool.shutdownNow(); for(Runnable task: remaining_tasks) { if(task instanceof Future) { Future future=(Future)task; future.cancel(true); } } pool.getQueue().clear(); try { pool.awaitTermination(Global.THREADPOOL_SHUTDOWN_WAIT_TIME, TimeUnit.MILLISECONDS); } catch(InterruptedException e) { } } public void run() { while(Thread.currentThread() == runner) { try { final Task entry=queue.take(); submitToPool(entry); } catch(InterruptedException interrupted) { // flag is cleared and we check if the loop should be terminated at the top of the loop } catch(Throwable t) { log.error("failed submitting task to thread pool", t); } } } protected Future scheduleRecurring(Runnable work, TaskType type, long initial_delay, long delay, TimeUnit unit) { return doSchedule(new RecurringTask(work, type, initial_delay, delay, unit), initial_delay); } protected Future doSchedule(Task task, long initial_delay) { if(task.getRunnable() == null) throw new NullPointerException(); if (isShutdown()) return null; if(initial_delay <= 0) { submitToPool(task); return task; } return add(task); } protected void submitToPool(final Task entry) { try { pool.execute(entry); } catch(RejectedExecutionException rejected) { // only thrown if rejection policy is "abort" Thread thread=timer_thread_factory != null? timer_thread_factory.newThread(entry, "Timer temp thread") : new Thread(entry, "Timer temp thread"); thread.start(); } } protected Task add(Task task) { if(!isRunning()) return null; queue.add(task); return task; } protected boolean isRunning() { Thread tmp=runner; return tmp != null && tmp.isAlive(); } protected synchronized void startRunner() { stopRunner(); runner=timer_thread_factory != null? timer_thread_factory.newThread(this, "Timer runner") : new Thread(this, "Timer runner"); runner.start(); } protected synchronized void stopRunner() { Thread tmp=runner; runner=null; if(tmp != null) { tmp.interrupt(); try {tmp.join(500);} catch(InterruptedException e) {} } queue.clear(); } public static class Task implements Runnable, Delayed, Future { protected final Runnable runnable; // the task to execute protected long creation_time; // time (in ns) at which the task was created protected long delay; // time (in ns) after which the task should execute protected volatile boolean cancelled; protected volatile boolean done; public Task(Runnable runnable) { this.runnable=runnable; } public Task(Runnable runnable, long initial_delay, TimeUnit unit) { this.creation_time=System.nanoTime(); this.delay=TimeUnit.NANOSECONDS.convert(initial_delay, unit); this.runnable=runnable; if(runnable == null) throw new IllegalArgumentException("runnable cannot be null"); } public Runnable getRunnable() {return runnable;} public int compareTo(Delayed o) { long my_delay=getDelay(TimeUnit.NANOSECONDS), other_delay=o.getDelay(TimeUnit.NANOSECONDS); // return Long.compare(my_delay, other_delay); // JDK 7 only return (my_delay < other_delay) ? -1 : ((my_delay == other_delay) ? 0 : 1); } public long getDelay(TimeUnit unit) { // time (in ns) until execution, can be negative when already elapsed long remaining_time=delay - (System.nanoTime() - creation_time); return unit.convert(remaining_time, TimeUnit.NANOSECONDS); } public boolean cancel(boolean mayInterruptIfRunning) { boolean retval=!isDone(); cancelled=true; return retval; } public boolean isCancelled() {return cancelled;} public boolean isDone() {return done || cancelled;} public Object get() throws InterruptedException, ExecutionException {return null;} public Object get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { return null; } public void run() { if(isDone()) return; try { runnable.run(); } catch(Throwable t) { log.error("failed executing task " + runnable, t); } finally { done=true; } } public String toString() { return runnable.toString(); } } /** Tasks which runs more than once, either dynamic, fixed-rate or fixed-delay, until cancelled */ protected class RecurringTask extends Task { protected final TaskType type; protected final long period; // ns protected final long initial_delay; // ns protected int cnt=1; // number of invocations (for fixed rate invocations) public RecurringTask(Runnable runnable, TaskType type, long initial_delay, long delay, TimeUnit unit) { super(runnable, initial_delay, unit); this.initial_delay=TimeUnit.NANOSECONDS.convert(initial_delay, TimeUnit.MILLISECONDS); this.type=type; period=TimeUnit.NANOSECONDS.convert(delay, unit); if(type == TaskType.dynamic && !(runnable instanceof TimeScheduler.Task)) throw new IllegalArgumentException("Need to provide a TimeScheduler.Task as runnable when type is dynamic"); } public void run() { if(isDone()) return; super.run(); if(cancelled) return; done=false; // run again switch(type) { case dynamic: long next_interval=TimeUnit.NANOSECONDS.convert(((TimeScheduler.Task)runnable).nextInterval(), TimeUnit.MILLISECONDS); if(next_interval <= 0) { if(log.isTraceEnabled()) log.trace("task will not get rescheduled as interval is " + next_interval); done=true; return; } creation_time=System.nanoTime(); delay=next_interval; break; case fixed_rate: delay=initial_delay + cnt++ * period; break; case fixed_delay: creation_time=System.nanoTime(); delay=period; break; } add(this); // schedule this task again } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy