|
This is my last revision of this Cycle Based Task Manager. Thanks again to Lare96 and Ryley.
Task.java
TaskManager.javaCode:package com.evolution.engine.task; import java.util.Optional; /** * <p> * A dynamic mutable task ; which processes the context the abstract execute * method. Each task have a mutable delay that is initially set upon contruction * of the task, When the <code>currentTick</code> is equal to the * <code>delay</code> then the <code>execute</code> method will be called upon ; * this will continue to occur intill the task is canceled. * </p> * * <p> * Tasks contain a overridable method <code>onCancelation</code> which can be used * to context an event upon cancelation of a task. * </p> * * <p> * Tasks also contain an optional attachment to link the task with a specific object. * If there is not attachment by default the optional should return <code>Optional.empty()</code>. * </p> * * Author: Jon Hultin link: "http://www.rune-server.org/members/laura+bodewig/" * Type: Task * Date: Feb 1, 2015 * Time: 1:12:13 AM * */ public abstract class Task { /** * The name of the task. */ protected final String taskName; /** * The delay of the task. */ protected int delay; /** * The current tick of the task. */ protected int currentTick; /** * The cancelation flag. */ protected boolean canceled; /** * Constructs a new {@link #Task(String, int, boolean)} with a set task name * and delay. You can also flag the task to execute immediatly. * * @param taskName the name of this task. * @param delay the delay of this task. * @param execute will this task execute immediatly. */ public Task(String taskName, int delay, boolean execute) { this.taskName = taskName; this.delay = delay; this.currentTick = execute ? delay : 0; this.canceled = false; } /** * Processes the task to be executed. */ public final void process() { if (!canceled) { if (currentTick == delay) { this.execute(); this.currentTick = 0; } this.currentTick++; } } /** * Gets the delay of the task. * * @return the value of the delay. */ public final int getDelay() { return delay; } /** * Sets a new delay for the task. * * @param delay the new delay value. */ public final void setDelay(int delay) { this.delay = delay; } /** * Gets the name of the task. * * @return the name of the task. */ public final String getTaskName() { return taskName; } /** * Checks if the task is canceled. * * @return the current state of cancel. */ public final boolean isCanceled() { return canceled; } /** * Cancels the task and calls the <code>onCancelation</code> method. */ public final void cancel() { this.canceled = true; this.onCancelation(); } /** * The optional task attachment. * * @return the attachment object. */ public abstract Optional<Object> getAttachment(); /** * The tasks execution context method. */ public abstract void execute(); /** * An overridable skeleton method for an event to occur upon cancelation. */ public void onCancelation() { }; }
Code:package com.evolution.engine.task; import java.util.Arrays; import java.util.LinkedList; import java.util.Objects; import java.util.Optional; import java.util.Queue; import java.util.function.Predicate; /** * <p> * A manager which handles the scheduling, cancelation, removal, validation, and * execution of {@link task#Task}(s). * </p> * * Author: Jon Hultin link: "http://www.rune-server.org/members/laura+bodewig/" * Type: TaskManager * Date: Feb 1, 2015 * Time: 1:14:27 AM * */ public final class TaskManager { /** * A queue of {@link task#Task}(s) awaiting validation. */ private static final Queue<Task> validation = new LinkedList<>(); /** * A queue of {@link task#Task}(s) awaiting execution. */ private static final Queue<Task> validated = new LinkedList<>(); /** * Constructs a new {@link #TaskManager()} which will throw and exception because * this class doesn't need to be instanced. */ public TaskManager() { throw new UnsupportedOperationException("This class can't be instanced."); } /** * Processes the validation and execution of the {@link task#Task}(s). */ public static void process() { validation.removeIf(Objects::isNull); validated.removeIf(Objects::isNull); validation.removeIf(Task::isCanceled); validated.removeIf(Task::isCanceled); while (!validation.isEmpty()) { validated.add(validation.poll()); } validated.forEach(Task::process); } /** * Schedules a new {@link task#Task}. * * @param task the task being scheduled. */ public static void schedule(Task task) { validation.offer(task); } /** * Schedules an array of {@link task#Task}(s). * * @param tasks the tasks being scheduled. */ public static void schedule(Task... tasks) { Arrays.stream(tasks).forEach(TaskManager::schedule); } /** * Removes a specific {@link task#Task} directly from the {@link #validated} collection if it has an * attachment present. This method is only ment to be used with task that contain an attachment * use {@link #cancel(String)} otherwise. * * @param attachment the attachment linked to the task. * @param taskName the name of the task. */ public static void remove(Object attachment, String taskName) { Predicate<Task> attachedTo = task -> task.getAttachment().equals(Optional.of(attachment)); Predicate<Task> isNamed = task -> task.getTaskName().equals(taskName); Optional<Task> task = validated.stream().filter(attachedTo).filter(isNamed).findFirst(); task.ifPresent(validated::remove); } /** * Cancels a {@link task#Task} based on its name. * * @param taskName the name of the task being canceled. */ public static void cancel(String taskName) { validated.forEach(task -> { if (task.taskName.equals(taskName)) { task.cancel(); } }); } /** * Canceleds an array of {@link task#Task}(s) based on there names. * * @param taskNames the names of the tasks being canceled. */ public static void cancel(String... taskNames) { Arrays.stream(taskNames).forEach(TaskManager::cancel); } /** * Cancels all validated {@link task#Task}(s). */ public static void cancelAll() { validated.forEach(Task::cancel); } }
should be 'return Optional.empty();'Code:public Optional<Object> getAttachment() { return null; }
be sure you're comparing the value within the optional and not the actual optional instances!! (or it isn't going to work)Code:public static final void remove(Object attachment) { CURRENT_TASKS.stream().filter(t -> t.getAttachment().equals(Optional.ofNullable(attachment))).forEach(t -> t.cancel()); }
otherwise great job bro, looking tons better
These are not 'constants', just because they are marked static and final does not mean they are a constant by definition; constants are immutable in their instance and their contents.Code:/** * A queue of {@link task#Task}(s) that are processed after submittion before * being sent to {@link #CURRENT_TASKS}. */ public static final Queue<Task> TASK_PROCESSING_QUEUE = new LinkedList<Task>(); /** * A list of all the currently running {@link task#Task}(s). */ public static final List<Task> CURRENT_TASKS = new LinkedList<Task>();
Example:
What appears to be a 'constant' is actually not, when you call it you expect point at 1, 3 instead you get 5, 3Code:private static final Point POINT = new Point(1, 3); static { POINT.x = 5; // assume 'x' is public and not final, this is valid. }
Same for your collections.
Loosen up on your parenthesis, this isn't a dialect of Lisp; it looks unnatural.Code:TASK_PROCESSING_QUEUE.removeIf((t) -> (t == null)); TASK_PROCESSING_QUEUE.removeIf((t) -> !(t.isRunning())); TASK_PROCESSING_QUEUE.forEach((t) -> (CURRENT_TASKS.add(TASK_PROCESSING_QUEUE.poll()))); CURRENT_TASKS.removeIf((t) -> !(t.isRunning())); CURRENT_TASKS.forEach(t -> (t.process()));
Also here is a good place to use method referencing...
i.e:
Code:TASK_PROCESSING_QUEUE.removeIf((t) -> (t == null)); // will become -> TASK_PROCESSING_QUEUE.removeIf(Objects::isNull); // --- CURRENT_TASKS.forEach(t -> (t.process())); // will become -> CURRENT_TASKS.forEach(Task::process);You should not be comparing objects like this, .equals.Code:t.getAttachment().get() == attachment
Also you should rarely be using Optional#get method anyway; use its built-in streams:
Example:
Code:Task task = ... task.getAttachment().isPresent(task -> { ... });The exception is redundant, Preconditions#checkArgument has a method which accepts a String as the error message (and will throw it if an error occurs)Code:Preconditions.checkArgument(delay > 0, new IllegalStateException("A task delay can't be less than or equal to 0."));
I understand that this method accepts different exception types to provide more readable or helpful information for debugging an error, but here it is unnecessary.
The default IllegalArgumentException is sufficient.
Diamond operator has existed since Java 7, use it. :- )Code:new LinkedList<Task>();
Thanks for the feedback will update when I get back from work.
Another note; do not mark static methods final, it serves no purpose.
Do not mark methods final if they are within a final class
Do mark methods final if they are at risk of being overridden and should not be.
This can still be shortened up:Code:processingTasks.removeIf(task -> task == null); // *snip* runningTasks.forEach(task -> task.process());
Code:processingTasks.removeIf(Objects::isNull); runningTasks.forEach(Task::process);
Hi again;
If you were to use the least specific type here, choose one or the other, List or Queue (LinkedList implements both)Code:/** * A queue of {@link task#Task}(s) that are processed after submittion before * being sent to {@link #runningTasks}. */ public static Queue<Task> processingTasks = new LinkedList<>(); /** * A list of all the currently running {@link task#Task}(s). */ public static List<Task> runningTasks = new LinkedList<>();
Also when I told you to not finalize static methods, that did not apply to fields, these collection instances are now mutable and should not be.
Hi there, what is that operator/expression called? "::"
@OP I've implemented a similar system into my application(s), however I tend to create my own composite task executor. Its basically a task executor (with extra functionality) but contains declares a ScheduledExecutorService to execute given tasks. Therefore tasks can be executed simultaneous and are asynchronous.
« Previous Thread | Next Thread » |
Thread Information |
Users Browsing this ThreadThere are currently 1 users browsing this thread. (0 members and 1 guests) |