JAVA版调度器

2021-04-15· 998 次浏览

JAVA版调度器

package cn.itsub.tank.timer; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; /** 调度器:可以在预定的时间执行回调 回调有两种: -- 更新回调:每一帧都会执行回调 -- 自定义回调:指定间隔时间执行回调, 推荐使用更新回调 * @site http://itsub.cn * @author Erik.Xia */ public class Scheduler { // 用于记录"目标-回调-优先级"的双链表 private static class tListEntry { public Method impMethod; public UpdateCallback callback; public Object target; public int priority; public boolean paused; }; // 用于记录"目标-计时-状态" private static class tHashSelectorEntry { ArrayList<MyTimer> timers; Object target; ArrayList<tListEntry> list; tListEntry entry; int timerIndex; MyTimer currentTimer; boolean currentTimerSalvaged; boolean paused; void setPaused(boolean b){ paused = b; if (entry != null){ entry.paused = b; } } } //按优先级区分 ArrayList<tListEntry> updatesNeg; // list priority < 0 ArrayList<tListEntry> updates0; // list priority == 0 ArrayList<tListEntry> updatesPos; // list priority > 0 ArrayList[] updatesArray = null; //按回调类型区分 ConcurrentHashMap<Object, tHashSelectorEntry> hashForSelectors; ConcurrentHashMap<Object, tHashSelectorEntry> hashForUpdates; tListEntry currentEntry; tHashSelectorEntry currentTarget; boolean currentTargetSalvaged; String updateSelector; /** * 时间流速,默认值1.0 * 当值小于1时为慢动作,当值快于1时为快动作 * @warning 它会影响所有的调度任务. */ private float timeScale_; public float getTimeScale() { return timeScale_; } public void setTimeScale(float ts) { timeScale_ = ts; } private static Scheduler _sharedScheduler = null; /** 返回单例的调度器 */ public static Scheduler getInstance() { if (_sharedScheduler != null) { return _sharedScheduler; } synchronized (Scheduler.class) { if (_sharedScheduler == null) { _sharedScheduler = new Scheduler(); } return _sharedScheduler; } } /** * 清除单例的调度器 */ public static void purgeSharedScheduler() { _sharedScheduler = null; } private Scheduler() { timeScale_ = 1.0f; // 触发时基于反射调用的方法名 updateSelector = "update"; // updates with priority updates0 = new ArrayList<tListEntry>(); updatesNeg = new ArrayList<tListEntry>(); updatesPos = new ArrayList<tListEntry>(); updatesArray = new ArrayList[]{updatesNeg, updates0, updatesPos}; hashForUpdates = new ConcurrentHashMap<Object, tHashSelectorEntry>(); hashForSelectors = new ConcurrentHashMap<Object, tHashSelectorEntry>(); // selectors with interval currentTarget = null; currentTargetSalvaged = false; } /** * 滴答(你不应该调用这个方法,除非你知道你在做什么) */ public void tick(float dt) { if( timeScale_ != 1.0f ) dt *= timeScale_; currentTargetSalvaged = false; for (int n = 0; n < updatesArray.length; n++) { ArrayList<tListEntry> list = updatesArray[n]; synchronized (list) { try { for (int i = 0; i < list.size(); i++) { tListEntry e = list.get(i); currentEntry = e; if( ! e.paused ) { if(e.callback !=null) { e.callback.update(dt); } else { try { e.impMethod.invoke(e.target, dt); } catch (InvocationTargetException e1) { if(e1.getTargetException() instanceof RuntimeException) throw (RuntimeException)e1.getTargetException(); else e1.printStackTrace(); } catch (Exception e1) { e1.printStackTrace(); } } if(currentTargetSalvaged) { list.remove(e); i--; currentTargetSalvaged = false; } } } } catch(IndexOutOfBoundsException e) { e.printStackTrace(); } currentEntry = null; } } Iterator<Entry<Object, tHashSelectorEntry>> it = hashForSelectors.entrySet().iterator(); while(it.hasNext()){ Entry<Object, tHashSelectorEntry> e = it.next(); tHashSelectorEntry elt = e.getValue(); currentTarget = elt; currentTargetSalvaged = false; if( ! currentTarget.paused && elt.timers != null) { // Timers数组可能在循环中更改。 for( elt.timerIndex = 0; elt.timerIndex < elt.timers.size(); elt.timerIndex++) { elt.currentTimer = elt.timers.get(elt.timerIndex); elt.currentTimerSalvaged = false; elt.currentTimer.update(dt); if( elt.currentTimerSalvaged ) { elt.currentTimer = null; } } } // 如果没有行动计划则删除currentTarget if( currentTargetSalvaged && currentTarget.timers.isEmpty()) { hashForSelectors.remove(elt.target); } } currentTarget = null; } static class SchedulerTimerAlreadyScheduled extends RuntimeException { private static final long serialVersionUID = -3460936783625533341L; public SchedulerTimerAlreadyScheduled(String reason) { super(reason); } } static class SchedulerTimerNotFound extends RuntimeException { private static final long serialVersionUID = -1912889437889458701L; public SchedulerTimerNotFound(String reason) { super(reason); } } /** * 每隔一段时间都会执行一次target对象的方法,selector用于指定方法名称,interval是间隔秒数, * 如果interval为0,则每一帧都会执行,如果这样,我们推荐使用'scheduleUpdateForTarget' */ public void schedule(String selector, Object target, float interval, boolean paused) { assert selector != null: "Argument selector must be non-nil"; assert target != null: "Argument target must be non-nil"; tHashSelectorEntry element = hashForSelectors.get(target); if( element == null ) { element = new tHashSelectorEntry(); element.target = target; hashForSelectors.put(target, element); element.paused = paused; } else { assert element.paused == paused : "Scheduler. Trying to schedule a selector with a pause value different than the target"; } if( element.timers == null) { element.timers = new ArrayList<MyTimer>(); } MyTimer timer = new MyTimer(target, selector, interval); element.timers.add(timer); } /** * 向target对象添加计时任务,每隔一段时间都会执行一次callback, * interval是间隔秒数,如果interval为0,则每一帧都会执行 */ public void schedule(UpdateCallback callback, Object target, float interval, boolean paused) { assert callback != null: "Argument callback must be non-nil"; assert target != null: "Argument target must be non-nil"; tHashSelectorEntry element = hashForSelectors.get(target); if( element == null ) { element = new tHashSelectorEntry(); element.target = target; hashForSelectors.put(target, element); element.paused = paused; } else { assert element.paused == paused : "HiScheduler. Trying to schedule a selector with a pause value different than the target"; } if( element.timers == null) { element.timers = new ArrayList<MyTimer>(); } MyTimer timer = new MyTimer( callback, interval); element.timers.add(timer); } /** * 从目标上移除指定方法名的任务 */ public void unschedule(String selector, Object target) { if( target==null || selector==null) return; assert target != null: "Target MUST not be null"; assert selector != null: "Selector MUST not be null"; tHashSelectorEntry element = hashForSelectors.get(target); if( element != null ) { for( int i=0; i< element.timers.size(); i++ ) { MyTimer timer = element.timers.get(i); if(selector.equals(timer.getSelector())) { if( timer == element.currentTimer && !element.currentTimerSalvaged ) { element.currentTimerSalvaged = true; } element.timers.remove(i); if( element.timerIndex >= i ) element.timerIndex--; if( element.timers.isEmpty()) { if( currentTarget == element ) { currentTargetSalvaged = true; } else { hashForSelectors.remove(element.target); } } return; } } } } /* * 从目标上移除callback任务 */ public void unschedule(UpdateCallback callback, Object target) { // 显式地处理零参数去除对象时 if( target==null || callback==null) return; assert target != null: "Target MUST not be null"; assert callback != null: "Selector MUST not be null"; tHashSelectorEntry element = hashForSelectors.get(target); if( element != null ) { for( int i=0; i< element.timers.size(); i++ ) { MyTimer timer = element.timers.get(i); if(callback == timer.getCallback()) { if( timer == element.currentTimer && !element.currentTimerSalvaged ) { element.currentTimerSalvaged = true; } element.timers.remove(i); if( element.timerIndex >= i ) element.timerIndex--; if( element.timers.isEmpty()) { if( currentTarget == element ) { currentTargetSalvaged = true; } else { hashForSelectors.remove(element.target); } } return; } } } } /** * 注销目标身上的Update任务 */ public void unscheduleUpdate(Object target) { if( target == null ) return; tHashSelectorEntry entry = hashForUpdates.get(target); if ( entry == null ) return; synchronized (entry.list) { if(currentEntry==entry.entry) { currentTargetSalvaged = true; } else { entry.list.remove(entry.entry); } } hashForUpdates.remove(target); } /** * 注销目标所有的任务 */ public void unscheduleAllSelectors(Object target) { if( target == null )return; // 注销'自定义选择器' tHashSelectorEntry element = hashForSelectors.get(target); if( element != null) { if(!element.currentTimerSalvaged ) { element.currentTimerSalvaged = true; //标记为可移除 } element.timers.clear(); if( currentTarget == element ) currentTargetSalvaged = true; //标记为可移除 else { hashForSelectors.remove(element.target); } } // 注销'Update选择器' this.unscheduleUpdate(target); } /** * 取消所有调度任务(不要调用这个方法,除非你知道自己在做什么) */ public void unscheduleAllSelectors() { // 遍历'自定义选择器' Iterator<Entry<Object, tHashSelectorEntry>> it = hashForSelectors.entrySet().iterator(); while(it.hasNext()){ Entry<Object, tHashSelectorEntry> e = it.next(); tHashSelectorEntry element = e.getValue(); Object target = element.target; unscheduleAllSelectors(target); } // 遍历'Update选择器' for (tListEntry entry:updates0) { unscheduleUpdate(entry.target); } for (tListEntry entry:updatesNeg) { unscheduleUpdate(entry.target); } for (tListEntry entry:updatesPos) { unscheduleUpdate(entry.target); } } /** * 恢复目标的调度任务,如果参数为空则什么也不发生 */ public void resume(Object target) { assert target != null: "target must be non nil"; // Custom Selectors tHashSelectorEntry element = hashForSelectors.get(target); if( element != null ) element.paused = false; // Update selector tHashSelectorEntry elementUpdate = hashForUpdates.get(target); if( elementUpdate != null) { assert elementUpdate.target != null: "resumeTarget: unknown error"; elementUpdate.setPaused(false); } } /** * 暂停目标的调度任务,如果参数为空则什么也不发生 */ public void pause(Object target) { assert target != null: "target must be non nil"; // Custom selectors tHashSelectorEntry element = hashForSelectors.get(target); if( element != null ) element.paused = true; // Update selectors tHashSelectorEntry elementUpdate = hashForUpdates.get(target); if( elementUpdate != null) { assert elementUpdate.target != null:"pauseTarget: unknown error"; elementUpdate.setPaused(true); } } /** * 给目标注册一个指定优先级的任务。每一帧都会调用目标的update方法。优先级越低,它被调用的越早。 * @param target 目标 * @param priority 优先级 * @param paused 是否暂停 */ public void scheduleUpdate(Object target, int priority, boolean paused) { // if (Config.DEBUG) { // tHashSelectorEntry hashElement = hashForUpdates.get(target); // assert hashElement == null:"Scheduler: You can't re-schedule an 'update' selector'. Unschedule it first"; // } // 大部分的更新都是0 if( priority == 0 ) { this.append(updates0, target, paused); } else if( priority < 0 ) { this.priority(updatesNeg, target, priority, paused); } else { // priority > 0 this.priority(updatesPos, target, priority, paused); } } /** * 给目标注册一个指定优先级的任务。每一帧都会调用目标的update方法。优先级越低,它被调用的越早。 * @param target 目标 * @param priority 优先级 * @param paused 是否暂停 */ public void scheduleUpdate(UpdateCallback target, int priority, boolean paused) { // if (Config.DEBUG) { // tHashSelectorEntry hashElement = hashForUpdates.get(target); // assert hashElement == null:"HiScheduler: You can't re-schedule an 'update' selector'. Unschedule it first"; // } if( priority == 0 ) { this.append(updates0, target, paused); } else if( priority < 0 ) { this.priority(updatesNeg, target, priority, paused); } else { // priority > 0 this.priority(updatesPos, target, priority, paused); } } @Override public void finalize () throws Throwable { unscheduleAllSelectors(); _sharedScheduler = null; super.finalize(); } public void append(ArrayList<tListEntry> list, Object target, boolean paused) { tListEntry listElement = new tListEntry(); listElement.target = target; listElement.paused = paused; if(target instanceof UpdateCallback) { listElement.callback = (UpdateCallback)target; } else { try { listElement.impMethod = target.getClass().getMethod(updateSelector, Float.TYPE); } catch (NoSuchMethodException e) { e.printStackTrace(); } } synchronized (list) { list.add(listElement); } tHashSelectorEntry hashElement = new tHashSelectorEntry(); hashElement.target = target; hashElement.list = list; hashElement.entry = listElement; hashForUpdates.put(target, hashElement); } public void priority(ArrayList<tListEntry> list, Object target, int priority, boolean paused) { tListEntry listElement = new tListEntry(); listElement.target = target; listElement.priority = priority; listElement.paused = paused; if(target instanceof UpdateCallback) { listElement.callback = (UpdateCallback)target; } else { try { listElement.impMethod = target.getClass().getMethod(updateSelector, Float.TYPE); } catch (NoSuchMethodException e) { e.printStackTrace(); } } synchronized (list) { if(list.isEmpty()) { list.add(listElement); } else { boolean added = false; int len = list.size(); for( int i = 0; i < len; i++ ) { tListEntry elem = list.get(i); if( priority < elem.priority ) { list.add(i, listElement); added = true; break; } } // Not added? priority has the higher value. Append it. if( !added ) list.add(listElement); } } tHashSelectorEntry hashElement = new tHashSelectorEntry(); hashElement.target = target; hashElement.list = list; hashElement.entry = listElement; hashForUpdates.put(target, hashElement); } }