定时任务,客户页面操作,使用java.util.timer(要求时间精确度不高的定时任务)
- 定时任务,客户页面操作,使用java.util.timer,因为@schedule 注解中定时的时间不能在不启动项目情况下修改。
- timer.cancel()任务队列全部移除,task.cancel()只移除队列中的一个任务。
- 页面操作定时任务,传递参数(访问任务接口URL和对应参数),修改timer 中Task,修改需要先移除Task.cancel()。
- 注意timer只能有一个对象,因为多个就会造成多线程定时任务(多线程需要保证每个队列timer中任务不重复)。
如果定时任务要求分布式请使用quartz
好了,不多说 上代码:这里数据是存的Redis。
//线程安全map:ConcurrentHashMap private Map<String, AutoEvalTask> timerTaskMap ;//<userName+taskName,timerTask> private Timer timer ;//不能放到方法里边,new 一个启动一个线程//启动了一个新线程,这个新线程并不是守护线程,所以会一直运行 public Timer getTimer() { return timer; } public void setTimer(Timer timer) { this.timer = timer; } //AutoEvalTask task = new AutoEvalTask();//不能放到方法里边, /** * 启动所有定时任务 * @param firstTimeStr * @param periodStr 秒数 * @return */ @RequestMapping(value="/lanchAllTimerTask") @ResponseBody public Map<String, String> lanchAllTimerTask() { Map<String, String> res = new HashMap<String, String>(); try { Map<Object, Object> hmget = redisUtil.hmget("seller_schedule_time_list"); for (Entry<Object, Object> map : hmget.entrySet()) { String key = (String) map.getKey();//username+taskName UserScheduleTimes value = (UserScheduleTimes) map.getValue();//定时任务信息对象 if (CollectionUtils.isEmpty(timerTaskMap)) { timerTaskMap = new ConcurrentHashMap<String, AutoEvalTask>(); } AutoEvalTask task = timerTaskMap.get(key); if (task!=null) { task.cancel();//从定时任务队列中移除 } if (timer==null) { timer = new Timer();//只有一个此定时任务队列。 } task = new AutoEvalTask();//定时任务对象 //task = SpringContextHolder.getBean("autoEvalTask");//会报异常 java.lang.IllegalStateException: Task already scheduled or cancelled task.setUserScheduleTimes(value); timerTaskMap.put(key, task); if (value !=null) { Date HHmmDate = value.getFirstTime(); Date executeDate = getExecuteDate(HHmmDate); timer.schedule(task, executeDate, value.getPeriod()*1000);//如果时间在当前时间之前,立即执行。然后间隔时间再次执行。 } LOGGER.info("key:"+key+",value:"+value); } res.put("status", "succ"); } catch (Exception e) { LOGGER.info("lanchAllTimerTask方法异常!",e); e.printStackTrace(); res.put("status", "fail"); } return res; } /** * 获取执行定时任务时刻,如果是当前时刻之前 第二天此时刻开始执行 * @param HHmmDate * @return */ private Date getExecuteDate(Date HHmmDate) { Calendar now = Calendar.getInstance(); Date executeDate = new Date(now.get(Calendar.YEAR) - 1900, now.get(Calendar.MONTH), now.get(Calendar.DAY_OF_MONTH), HHmmDate.getHours(), HHmmDate.getMinutes(), HHmmDate.getSeconds()); if (executeDate.compareTo(new Date())<0) {//不加此设置,如果是当前时刻 立即执行 executeDate = DatesUtils.getTimePeriodBeforeDate(-1, executeDate);//1天后的此时刻执行任务。(最准确是开始时间+间隔倍数 大于当前时间最近的时间) } return executeDate; }
/** * 定时任务类 * @author zel * @date 2019年7月22日 下午8:44:35 * */ @Component public class AutoEvalTask extends TimerTask{ private static final Logger LOGGER = LoggerFactory.getLogger(AutoEvalTask.class); //@Autowired AutoEvaluateTask autoEvaluateTask = SpringContextHolder.getBean("autoEvaluateTask");//外边AutoEvalTask是new的则不会注入 private UserScheduleTimes userScheduleTimes; public UserScheduleTimes getUserScheduleTimes() { return userScheduleTimes; } public void setUserScheduleTimes(UserScheduleTimes userScheduleTimes) { this.userScheduleTimes = userScheduleTimes; } /* (non-Javadoc) * @see java.util.TimerTask#run() */ @Override public void run() { try { //String url = "http://192.168.1.10:30002/tradeserver/delaysendmsg.api/scheduleTask/autoEvaluateInterface"; String url = this.userScheduleTimes.getUrl(); Map<String, String> param = this.userScheduleTimes.getParam(); String userName = param.get("userName"); if (userName.indexOf(",")!=-1) { String[] split = userName.split(","); for (int i = 0; i < split.length; i++) { LOGGER.info(split[i] + ",多个用户测试定时任务"); //autoEvaluateTask.autoEvaluateAllFinished2(split[i], "35"); Map<String, String> paramInterfaceUrl = new HashMap<String, String>(); paramInterfaceUrl.put("userName", split[i]); String httpGetWithJSON = HttpClientUtil.httpGetWithJSON(url, paramInterfaceUrl); LOGGER.info("定时任务"+this.userScheduleTimes.getTaskName()+"结果:"+httpGetWithJSON); } } else {//单个用户 LOGGER.info(userName + ",单个测试定时任务"); //autoEvaluateTask.autoEvaluateAllFinished2(userName, "35"); String httpGetWithJSON = HttpClientUtil.httpGetWithJSON(url, param); LOGGER.info("定时任务"+this.userScheduleTimes.getTaskName()+"结果:"+httpGetWithJSON); } } catch (Exception e) { e.printStackTrace(); LOGGER.info("定时任务run方法异常!",e); } }
相关实体类entity:
/** * 客户设置的定时任务 时间点和 间隔时长, * @author zel * @date 2019年7月19日 下午12:16:51 * */ public class UserScheduleTimes implements Serializable{ /** * */ private static final long serialVersionUID = 8534961773338501488L; private String taskName;//定时任务名称 //url 及参数信息: private String url;//定时执行URL,并附带参数。 private Map<String, String> param;//参数,transient:不被序列化 // private String userName;//多用户逗号隔开 // private String orderTime;//订单时间 // private String type;//"manyUser":多用户 。 //任务参数 private Date firstTime;//任务开始执行时间。 private Long period;//任务间隔时长 单位/秒 public Map<String, String> getParam() { return param; } public void setParam(Map<String, String> param) { this.param = param; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getTaskName() { return taskName; } public void setTaskName(String taskName) { this.taskName = taskName; } public Date getFirstTime() { return firstTime; } public void setFirstTime(Date firstTime) { this.firstTime = firstTime; } public Long getPeriod() { return period; } public void setPeriod(Long period) { this.period = period; } @Override public String toString() { return "UserScheduleTimes [taskName=" + taskName + ", url=" + url + ", param=" + param + ", firstTime=" + firstTime + ", period=" + period + "]"; } }
源码,是痛苦的,又是快乐的,如果没有这痛苦,也就没有了这快乐!