JAVA版调度器

2021-04-15· 697 次浏览
JAVA版调度器 ```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 &##124;&##124; 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 &##124;&##124; 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);     } } ```