Really couldn't think of anything else to call it, but it's pretty much what it does, it will handle the appropriate phase, but on the last phase it's handled in a separate method (easy way to describe). Anyways, documentation explains it all.
package phaser; /** * A simple abstract class that is used for representing an action that <ii>must</ii> * be performed in <b>phases.</b> I will allow myself to elabored: * <p> * A phaser (example) can be someone so simple as used in the runescape protocol * for things like <ii>agility,</ii> say we have phase 1, the player will walk * back from an object, then at phase 2 the wil force run and perform the * animation for the object, then at the final phase the player will receive XP * and many other things that may aquire. * </p> * * @author Thomas Le Godais */public abstract class Phaser { /** * An integer that is used to represent how many <b>phases</b> <ii>this</ii> * phaser should have. */ private int phaseCount; /** * An integer that is used to represent the delay that we're going to be * starting the tick. */ private int delayTime; /** * An integer that is used to represent the delay between the <b>periodic * ticks</b> of the phaser. */ private int periodicTime; /** * An integer that is used to represent the current phase we're handling. */ private int currentPhase = 0; /** * Constructs a new {@code Phaser} instance. * * @param phaseCount * The amount of phases that this current phaser has. * @param delayTime * The amount of time to delay the phaser before starting. * @param periodicTime * The amount of time in which we <ii>tick</ii> the phaser. */ public Phaser(int phaseCount, int delayTime, int periodicTime) { this.phaseCount = phaseCount; this.delayTime = delayTime; this.periodicTime = periodicTime; } /** * Handles the set amount of phases. * <p> * The user will set the amount of "phases" that we will go through, then * from there we will cycle through them (they can or can not have a delay). * This will handle every phase - 1, the final phase is handled in it's own * method). * </p> * * @param currentPhase * The current phase that we're currently processing for, please * note <b>this will only cycle the amount of phases, but minus * the last one because we're not processing for it</b>. */ public abstract void handlePhase(int currentPhase); /** * This is used to process the final phase, not this can just be something * simple as (in the runescape protocol) a player receiving expereince for * the task they performed (skill-wise). Or it can be used to process * certain tasks that a player needs (no examples come to mind, sorry). */ public abstract void finalPhase(); /** * Gets the amount of max phases <b>this</b> phaser should cycle! * * @return the phaseCount */ public int getPhaseCount() { return phaseCount; } /** * Gets the amount of time in which to delay the initial start of the * phaser. * * @return the delayTime */ public int getDelayTime() { return delayTime; } /** * Gets the periodic <ii>tick</ii> time of the phaser. * * @return the periodicTime */ public int getPeriodicTime() { return periodicTime; } /** * Gets the current phase of this tick. * * @return the currentPhase */ public int getCurrentPhase() { return currentPhase; } /** * Sets the current phase (currentPhase + 1). * * @param currentPhase the currentPhase to set */ public void setCurrentPhase(int currentPhase) { this.currentPhase = currentPhase; } /** * Sets the phase count. * * @param phaseCount the phaseCount to set */ public void setPhaseCount(int phaseCount) { this.phaseCount = phaseCount; } /** * Sets the delay time. * * @param delayTime the delayTime to set */ public void setDelayTime(int delayTime) { this.delayTime = delayTime; } /** * Sets the period time. * * @param periodicTime the periodicTime to set */ public void setPeriodicTime(int periodicTime) { this.periodicTime = periodicTime; }}
package phaser; import java.util.Collections;import java.util.Iterator;import java.util.LinkedList;import java.util.List; /** * An {@link Thread} that will be used to listen to <b>incoming</b> * {@link Phaser} requests to a list. * <p> * This list will be cycle every certain amount of ms (milliseconds). And once * the thread has finished all of its phases {@see Phaser#finalPhase()} the * {@link Phaser} will then be removed from the list, and not be handled anymore * by this thread. * </p> * * @author Thomas Le Godais * */public class PhaseProcessor extends Thread { /** * An constant that is used to represent the tick at which this cycles * (being default 600ms!). */ private static final long CYCLE_COUNT = 600; /** * A simple flag that is used to indicate if the thread processor should be * running. */ private boolean threadStarted = false; /** * An {@link List} that is used for adding/removing phasers from/to. * <p> * The reason that we're using a synchronized list, is for example say we're * on the main thread (in RSPS sense the game thread, and we add/remove a * phaser, we <b>do not</b> want to cause <ii>synchronization</ii> * exceptions between the 2 threads because they will not be <ii>synced</ii> * with each other. * </p> */ private List<Phaser> phasers = Collections.synchronizedList(new LinkedList<Phaser>()); /** * Constructs a new {@code PhaseProcessor} instance. * <p> * Here we're are going to set the name of the thread (this is useful if an * error occurs in this thread, instead of it labelling it by the thread-ID * we can know the thread right away[incase we have many threads in a * application]). And since this is a really important part of an * application (may be used to perform high priority updates) this is a MAX * priority thread. * </p> */ public PhaseProcessor() { this.setName("Phase-Processor-Thread"); this.setPriority(Thread.MAX_PRIORITY); } /* * (non-Javadoc) * * @see java.lang.Thread#run() */ @Override public void run() { while (isThreadStarted()) { /* Get the current time we starting handling the phaser. */ long currentTime = System.currentTimeMillis(); /* * Prevent the thread from processing because there is no phasers to * currently handle. */ if (phasers.isEmpty()) return; /* * Iterate through the list to get all of the current phasers, only * if the list is not empty. */ for (Iterator<Phaser> it$ = phasers.iterator(); it$.hasNext();) { /* * Check to make sure a phaser is not {@code Null} in the list. * * If the phaser is {@code Null} we're going to "continue" * because we do not want to halt all of the other phasers that * could possibly cycling! */ Phaser phaser = (Phaser)it$.next(); if (phaser == null) continue; /* * This block of code is used to check if we still have time * left before we're going to process a task. * * If we do have time left we're going to subtract one ms * (millisecond) from it, and then we're going to "continue" * because we do not want to stop processing other tasks that * may exist! */ if (phaser.getDelayTime() > 0) { phaser.setDelayTime(phaser.getDelayTime() - 1); continue; } /* * Next, we're going to cycle the phaser! But, we have to make * sure we increment the current phase (only if it's not the * final phase)! But, if it's the final phase we're going to * handle the other method {@see Phaser#finalPhase()} instead of * {@see Phaser#handlePhase()}. */ int maxPhase = phaser.getPhaseCount(); /* * A simple flag used to indicate if we should remove this * phaser from processing (only called on the final state)! */ boolean shouldRemove = false; if (phaser.getCurrentPhase() != maxPhase) { phaser.setCurrentPhase(phaser.getCurrentPhase() + 1); phaser.handlePhase(phaser.getCurrentPhase()); } else { phaser.finalPhase(); shouldRemove = true; } /* * Finally we're going to have to decide if we should either * remove the current phaser (to stop processing) or, are we * going to reset the delay between each phase (if exists!). */ if (shouldRemove) phasers.remove(phaser); else { phaser.setDelayTime(phaser.getPeriodicTime()); } /* * Here we're going to get the total time it took to process the * phaser! */ long totalTime = CYCLE_COUNT + (System.currentTimeMillis() - currentTime); /* * If the total time is less then zero we're going to prevent it * from sleeping because we can not sleep at a negative count! */ if (totalTime < 0) continue; /* * And finally, to end this all off, we're going to sleep the * current thread after processing! */ try { Thread.sleep(totalTime); } catch (InterruptedException e) { e.printStackTrace(); } } } } /** * Submits a new {@link Phaser} into the {@link List} for processing! * * @param phaser The phaser we're adding into the list. */ public void submit(Phaser phaser) { if (phaser == null) return; phasers.add(phaser); } /** * Shutdown the phaser from processing! */ public void shutdown() { phasers.clear(); setThreadStarted(false); } /** * Gets the current list of phasers. * * @return The list. */ public synchronized List<Phaser> getPhasers() { return phasers; } /** * Gets the flag that is used to indicate if this thread should be * processing. * * @return the threadStarted */ public boolean isThreadStarted() { return threadStarted; } /** * Sets the value of the "threadStarted" flag. * * @param threadStarted the threadStarted to set */ public void setThreadStarted(boolean threadStarted) { this.threadStarted = threadStarted; }}
A small example
package phaser.test; import phaser.PhaseProcessor;import phaser.Phaser; public class Test { private static final PhaseProcessor phaseProcessor = new PhaseProcessor(); public static void main(String[] args) { /* First begin by starting the phaser cycle! */ phaseProcessor.setThreadStarted(true); phaseProcessor.start(); /* Now, we're going to submit a phase to the thread! */ phaseProcessor.submit(new Phaser(22, 0, 600) { /** * An integer used for testing the count. */ int testCount = 0; /* * (non-Javadoc) * @see phaser.Phaser#handlePhase(int) */ @Override public void handlePhase(int currentPhase) { if (currentPhase <= 5) System.out.println("Current phase is less than, or equal to 5!"); else if (currentPhase >= 10) System.out.println("Current phase is greater then or eqal to 10!"); else System.out.println("Phase was neither!"); testCount += 1; } /* * (non-Javadoc) * @see phaser.Phaser#finalPhase() */ @Override public void finalPhase() { System.out.println("Phaser finished at test count: " + testCount); } }); }}