0、序
在遊戲工程地開發過程中,定時器功能是一般遊戲必不可少的功能,同時,在其他類型的項目中,也會時常需要用到定時器的方法。例如遊戲中建造一個建築需要倒計時等。下面從單線程和多線程兩個方面實現定時器的功能。
1、單線程(schedule)
首先我們需要一個單獨的定時任務類,繼承TimerTask,用來表示具體的定時任務,單獨提出來封裝成一個類,方便管理和實現:
import java.util.TimerTask;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.Future;public class SystemTimerTask extends TimerTask{private long taskID;//任務IDprivate long runtime;//倒計時的具體時間(以秒為單位)private ConcurrentHashMap<Long, Future<Long>> futureMap; public SystemTimerTask(Long taskID,long runtime) {this.taskID = taskID;this.runtime = runtime;} @Override public void run() { System.out.println("Time Remain: "+this.runtime); if (this.runtime-- <= 0 ) { try { Future<Long> future = futureMap.remove(taskID); future.cancel(true); } finally { System.out.println("###### Task "+taskID +" is Completed!!"); } } }public long getRemaintime() { return runtime; }public long getTaskID() { return taskID; }}
在單線程的情況下,不需要考慮其他條件直接調用 schedule 方法即可實現,具體調用方法如下:
Timer timer = new Timer(); SystemTimerTask() task = new SystemTimerTask(10001,20);timer.schedule(task ,0,1000);
關於schedule 方法聲明為:schedule(TimerTask task, long delay, long period)
--task:被調度的定時任務;
--delay:以毫秒為單位,表示任務延遲delay毫秒後執行;
--period:以毫秒為單位,表示任務執行期間,也就是定時器初始值。
2、多線程(ScheduledExecutorService) 在實際應用開發中,單線程應用的範圍很窄,並發是項目開發中必不可少的需要考慮到的因素,在定時器實現中,採用多線程,可以更有效率地實現多個定時器並行作業,同時,可以在一個大的項目中,對定時任務線程實施更方便地管理和查看。所以,我們在Java內建定時任務線程池ScheduledExecutorService基礎上,封裝成一個定時任務線程管理類,如下:
import java.util.Iterator;import java.util.concurrent.ConcurrentHashMap;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;//根據具體包名,將SystemTimerTask包含進來public class TimerManager { private static TimerManager instance; private TimerManager() { } public static TimerManager getInstance() { if(instance == null) { return new TimerManager(); } return instance; }private ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(); //初始化ScheduledExecutorService線程池,具體長度視情況而定private static ConcurrentHashMap<Long, SystemTimerTask> taskmap = new ConcurrentHashMap<Long, SystemTimerTask>();//採用以任務ID為key的雜湊表儲存所有實現的定時任務public boolean StartTimer(long id,long time,long initialDelay, long period, TimeUnit unit ) {if(taskmap.containsKey(id) ){return false;}else{SystemTimerTask task_time = new SystemTimerTask(id,time);this.addTask(id, task_time);Iterator keys = taskmap.keySet().iterator(); while(keys.hasNext()){ Long key = (Long)keys.next(); if(key == id) System.out.println("是否存在------------- "+ (key == id)+" id: "+id); } System.out.println("是否存在+++++++++++ "+ taskmap.get(id).getRemaintime()); this.service.scheduleAtFixedRate(task_time, initialDelay,period, unit);return true;}} public ScheduledExecutorService getService() {return service;}public void setService(ScheduledExecutorService service) {this.service = service;}public long getRemain(long id) {if(this.getTask().containsKey(id)){return this.getTask().get(id).getRemaintime();}elsereturn -1;}public ConcurrentHashMap<Long, SystemTimerTask> getTask() {return taskmap;}public void addTask( long id ,SystemTimerTask task1) {taskmap.put(id, task1) ;}}
以上將定時器管理類設定為單例模式,防止其他對象對自己執行個體化,確保所有對象訪問的都是一個執行個體。
scheduleAtFixedRate 方法的參數說明同上面的 Timer類中的 schedule 方法。可自行查閱。
以下為其測試主函數:
public static void main(String[] args) throws InterruptedException {long remain = 10;long remain2 = 20;System.out.println("Start:");long id1 = 100;long id2 = 110;TimerManager.getInstance().StartTimer(id1, remain, 0, 1, TimeUnit.SECONDS);TimerManager.getInstance().StartTimer(id2, remain2, 0, 1, TimeUnit.SECONDS);Thread.sleep(3000);System.out.println("是否存在::::"+ TimerManager.getInstance().getTask().containsKey(id1));System.out.println("+++++++++++++++++++++Time remain................ :"+TimerManager.getInstance().getRemain(id2));}
3、總結 在本文中,基於單線程和多線程兩種方式實現定時器的功能,兩種各有優缺點,合理採納。同時,在多線程實現中,有一點不足之處,在具體應用的時候希望改正,就是定時任務ID可以採用自動產生的增長序列,保證其唯一性,因為時間關係,本文尚未添加。