Timer方法API
Timer类主要负责计划任务的功能,也就是在指定的时间开始执行某一个任务。Timer类的主要作用就是设置计划任务,但封装任务的类却是 TimerTask类。执行计划任务的代码要放入 TimerTask的子类中(TimerTask类是实现Runnable接口的抽象类) 。
1. schedule(TimerTask task,Date date)
作用:在指定的日期执行一次某方法
public class TimerI extends TimerTask {
@Override
public void run() {
System.out.println("Timer定时执行!");
}
}
public class RunMain {
public static void main(String[] args) {
Timer timer = new Timer();
String runTime = "2019-03-01 15:42:00";
Date date = DateUtil.parse(runTime, DatePattern.NORM_DATETIME_PATTERN);
TimerI timerI = new TimerI();
timer.schedule(timerI, date);
}
}
TimerTask是以队列的方式按顺序执行的,执行的时间有可能和预期的不一致,因为前面的任务有可能消耗的时间较长,则后面的任务运行的时间也会被延迟。
2. schedule( TimerTask task, Date time, long period)
作用:在指定的日期开始,按指定的间隔周期性地无限循环地执行某一任务。
3. cancel()
TimerTask类中的 cancel方法的作用是将自身从任务队列中清除(其他任务没影响)
public class TimerI extends TimerTask {
@Override
public void run() {
System.out.println("TimerI 定时执行!");
this.cancel();
}
}
public class TimerII extends TimerTask {
@Override
public void run() {
System.out.println("TimerII 定时执行!");
}
}
public class RunMain {
public static void main(String[] args) {
Timer timer = new Timer();
String runTime = "2019-03-01 16:24:00";
Date date = DateUtil.parse(runTime, DatePattern.NORM_DATETIME_PATTERN);
TimerI timerI = new TimerI();
TimerII timerII = new TimerII();
timer.schedule(timerI, date,22);
timer.schedule(timerII,date,30);
}
}
运行结果:
Timer类中的 cancel() 方法的作用是将任务队列中的全部任务清空
4. schedule( TimerTask task, long delay)
作用:以当前的时间为参考,延迟指定的毫秒数后执行一次 TimerTask任务。
5. schedule( TimerTask task, long delay, long period)
作用:以当前的时间为参考,延迟指定的毫秒数,以某一间隔时间无限次数地执行某一任务。
6. scheduleAtFixedRate(Timer Task task, Date time, long period)
schedule和 scheduleAtFixed Rate主要的区别:
① 使用 schedule方法:如果执行任务的时间没有被延时,那么下一次任务的执行时间参考上一次任务的“开始”时的时间来计算
使用 scheduleAtFixedRate方法:如果执行任务的时间没有被延时,那么下一次任务的执行时间参考上一次任务的“结束”时的时间来计算。
② schedule方法不具有追赶执行性(即 计划时间早于当前时间时,只从当前时间开始执行),scheduleAtFⅸedRate方法具有追赶执行性(即 计划时间早于当前时间时,从计划时间补充性的开始执行)
单例模式
在多线程环境中,使用懒汉模式的单例模式会出现非线程安全问题
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
}
public static LazySingleton getInstance() throws InterruptedException {
if (instance != null) {
Thread.sleep(100);
instance = new LazySingleton();
}
return instance;
}
}
运行结果:
由结果可知多线程环境中,懒汉单例模式获取到的单例对象是线程不安全的!
解决办法:
① 使用synchronized同步方法获取实例对象,但同步方法运行效率比较低
② 双检查锁机制
SimpleDateFormat
SimpleDateFormat类主要负责日期的转换与格式化,但在多线程的环境中容易造成数据转换及处理的不准确。
public class ThreadIII extends Thread {
private SimpleDateFormat simple;
private String dateString;
public ThreadIII(SimpleDateFormat simple, String dateString) {
this.simple = simple;
this.dateString = dateString;
}
@Override
public void run() {
try {
Date date = simple.parse(dateString);
String newDate = simple.format(date).toString();
System.out.println("正确日期:" + dateString+" 输出时间:" + newDate);
} catch (ParseException e) {
e.printStackTrace();
}
}
}
public class RunMain {
public static void main(String[] args) {
SimpleDateFormat simple = new SimpleDateFormat("yyyy-MM-dd");
String[] dateArray = new String[]{"2019-01-22", "2018-11-12", "2019-02-02", "2018-12-22"};
ThreadIII[] threadIIIS = new ThreadIII[dateArray.length];
for (int i = 0; i < dateArray.length; i++) {
threadIIIS[i] = new ThreadIII(simple, dateArray[i]);
threadIIIS[i].start();
}
}
}
运行结果:
明显,运行结果数据异常!建议使用 DateTimeFormatter
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");