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

com.firefly.utils.time.HashTimeWheel Maven / Gradle / Ivy

There is a newer version: 5.0.2
Show newest version
package com.firefly.utils.time;

import com.firefly.utils.concurrent.Scheduler;
import com.firefly.utils.concurrent.ThreadUtils;
import com.firefly.utils.lang.AbstractLifeCycle;

import java.util.concurrent.ConcurrentLinkedQueue;

public class HashTimeWheel extends AbstractLifeCycle {

    private int maxTimers = 60; // slot's number in wheel
    private long interval = 1000; // the clock's accuracy

    private ConcurrentLinkedQueue[] timerSlots;
    private volatile int currentSlot = 0;

    public int getMaxTimers() {
        return maxTimers;
    }

    public void setMaxTimers(int maxTimers) {
        this.maxTimers = maxTimers;
    }

    public long getInterval() {
        return interval;
    }

    public void setInterval(long interval) {
        this.interval = interval;
    }

    /**
     * add a task
     *
     * @param delay after x milliseconds than execute runnable
     * @param run   run task in future
     * @return The task future
     */
    public Future add(long delay, Runnable run) {
        final int curSlot = currentSlot;

        final int ticks = delay > interval ? (int) (delay / interval) : 1; // figure out how many ticks need
        final int index = (curSlot + (ticks % maxTimers)) % maxTimers; // figure out the wheel's index
        final int round = (ticks - 1) / maxTimers; // the round number of spin

        TimerTask task = new TimerTask(round, run);
        timerSlots[index].add(task);

        return new Future(this, index, task);
    }

    private boolean remove(TimerTask task, int index) {
        return timerSlots[index].remove(task);
    }

    private final class Worker implements Runnable {

        @Override
        public void run() {
            while (start) {
                int currentSlotTemp = currentSlot;
                ConcurrentLinkedQueue timerSlot = timerSlots[currentSlotTemp++];
                currentSlotTemp %= timerSlots.length;
                timerSlot.removeIf(TimerTask::runTask);
                ThreadUtils.sleep(interval);
                currentSlot = currentSlotTemp;
            }
        }

    }

    private final class TimerTask {
        private int round;
        private Runnable run;

        public TimerTask(int round, Runnable run) {
            this.round = round;
            this.run = run;
        }

        public boolean runTask() {
            if (round == 0) {
                run.run();
                return true;
            } else {
                round--;
                return false;
            }
        }
    }

    public static class Future implements Scheduler.Future {
        private HashTimeWheel timeWheel;
        private int index;
        private TimerTask task;

        public Future(HashTimeWheel timeWheel, int index, TimerTask task) {
            super();
            this.timeWheel = timeWheel;
            this.index = index;
            this.task = task;
        }

        /**
         * cancel current task
         *
         * @return if it return true, which cancel task success, else it fail
         */
        @Override
        public boolean cancel() {
            return timeWheel.remove(task, index);
        }
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void init() {
        timerSlots = new ConcurrentLinkedQueue[maxTimers];
        for (int i = 0; i < timerSlots.length; i++) {
            timerSlots[i] = new ConcurrentLinkedQueue();
        }

        start = true;
        new Thread(new Worker(), "firefly time wheel").start();
    }

    @Override
    protected void destroy() {
        start = false;
        timerSlots = null;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy