我的世界java版单核调度
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;//任务ID private 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(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(); } else return -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可以采用自动生成的增长序列,保证其唯一性,因为时间关系,本文尚未添加。