Package l2p.commons.threading

Source Code of l2p.commons.threading.SteppingRunnableQueueManager$SteppingScheduledFuture

package l2p.commons.threading;

import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Delayed;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.RunnableScheduledFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.apache.commons.lang3.mutable.MutableLong;
import l2p.commons.collections.LazyArrayList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Менеджер очереди задач с кратным запланированным временем выполнения.
*
* @author G1ta0
*/
public abstract class SteppingRunnableQueueManager implements Runnable
{
  private static final Logger _log = LoggerFactory.getLogger(SteppingRunnableQueueManager.class);

  protected final long tickPerStepInMillis;
  private final List<SteppingScheduledFuture<?>> queue = new CopyOnWriteArrayList<SteppingScheduledFuture<?>>();
  private final AtomicBoolean isRunning = new AtomicBoolean();

  public SteppingRunnableQueueManager(long tickPerStepInMillis)
  {
    this.tickPerStepInMillis = tickPerStepInMillis;
  }

  public class SteppingScheduledFuture<V> implements RunnableScheduledFuture<V>
  {
    private final Runnable r;
    private final long stepping;
    private final boolean isPeriodic;

    private long step;
    private boolean isCancelled;

    public SteppingScheduledFuture(Runnable r, long initial, long stepping, boolean isPeriodic)
    {
      this.r = r;
      this.step = initial;
      this.stepping = stepping;
      this.isPeriodic = isPeriodic;
    }

    @Override
    public void run()
    {
      if(--step == 0)
        try
      {
          r.run();
      }
      catch(Exception e)
      {
        _log.error("Exception in a Runnable execution:", e);
      }
      finally
      {
        if (isPeriodic)
          step = stepping;
      }
    }

    @Override
    public boolean isDone()
    {
      return isCancelled || !isPeriodic && step == 0;
    }

    @Override
    public boolean isCancelled()
    {
      return isCancelled;
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning)
    {
      return isCancelled = true;
    }

    @Override
    public V get() throws InterruptedException, ExecutionException
    {
      return null;
    }

    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException
    {
      return null;
    }

    @Override
    public long getDelay(TimeUnit unit)
    {
      return unit.convert(step * tickPerStepInMillis, TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o)
    {
      return 0;
    }

    @Override
    public boolean isPeriodic()
    {
      return isPeriodic;
    }
  }

  /**
   * Запланировать выполнение задачи через промежуток времени
   * @param r задача для выполнения
   * @param delay задержка в миллисекундах
   * @return SteppingScheduledFuture управляющий объект, отвечающий за выполенение задачи
   */
  public SteppingScheduledFuture<?> schedule(Runnable r, long delay)
  {
    return schedule(r, delay, delay, false);
  }

  /**
   * Запланировать выполнение задачи через равные промежутки времени, с начальной задержкой
   * @param r задача для выполнения
   * @param initial начальная задержка в миллисекундах
   * @param delay период выполенения в силлисекундах
   * @return SteppingScheduledFuture управляющий объект, отвечающий за выполенение задачи
   */
  public SteppingScheduledFuture<?> scheduleAtFixedRate(Runnable r, long initial, long delay)
  {
    return schedule(r, initial, delay, true);
  }

  private SteppingScheduledFuture<?> schedule(Runnable r, long initial, long delay, boolean isPeriodic)
  {
    SteppingScheduledFuture<?> sr;

    long initialStepping = getStepping(initial);
    long stepping = getStepping(delay);

    queue.add(sr = new SteppingScheduledFuture<Boolean>(r, initialStepping, stepping, isPeriodic));

    return sr;
  }

  /**
   * Выбираем "степпинг" для работы задачи:
   * если delay меньше шага выполнения, результат будет равен 1
   * если delay больше шага выполнения, результат будет результатом округления от деления delay / step
   */
  private long getStepping(long delay)
  {
    delay = Math.max(0, delay);
    return delay % tickPerStepInMillis > tickPerStepInMillis / 2 ? delay / tickPerStepInMillis + 1 : delay < tickPerStepInMillis ? 1 : delay / tickPerStepInMillis;
  }

  @Override
  public void run()
  {
    if (!isRunning.compareAndSet(false, true))
    {
      _log.warn("Slow running queue, managed by " + this + ", queue size : " + queue.size() + "!");
      return;
    }

    try
    {
      if (queue.isEmpty())
        return;

      for(SteppingScheduledFuture<?> sr: queue)
        if(!sr.isDone())
          sr.run();
    }
    finally
    {
      isRunning.set(false);
    }
  }

  /**
   * Очистить очередь от выполенных и отмененных задач.
   */
  public void purge()
  {
    LazyArrayList<SteppingScheduledFuture<?>> purge = LazyArrayList.newInstance();

    for(SteppingScheduledFuture<?> sr: queue)
      if (sr.isDone())
        purge.add(sr);

    queue.removeAll(purge);

    LazyArrayList.recycle(purge);
  }

  public CharSequence getStats()
  {
    StringBuilder list = new StringBuilder();

    Map<String, MutableLong> stats = new TreeMap<String, MutableLong>();
    int total = 0;
    int done = 0;

    for(SteppingScheduledFuture<?> sr: queue)
    {
      if (sr.isDone())
      {
        done++;
        continue;
      }
      total++;
      MutableLong count = stats.get(sr.r.getClass().getName());
      if (count == null)
        stats.put(sr.r.getClass().getName(), count = new MutableLong(1L));
      else
        count.increment();
    }

    for(Map.Entry<String, MutableLong> e : stats.entrySet())
      list.append("\t").append(e.getKey()).append(" : ").append(e.getValue().longValue()).append("\n");

    list.append("Scheduled: ....... ").append(total).append("\n");
    list.append("Done/Cancelled: .. ").append(done).append("\n");

    return list;
  }
}
TOP

Related Classes of l2p.commons.threading.SteppingRunnableQueueManager$SteppingScheduledFuture

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.