一步一步学多线程-Timer

  在执行定时任务的时候可以用Timer来实现,现在小编对学到的进行一次总结,先来看一个demo

 1 public class TimerTest {
 2 
 3     public static void main(String[] args) throws ParseException {
 4         Date date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-08-17 11:18:00");
 5         new Timer().schedule(new TimerTask() {
 6             @Override
 7             public void run() {
 8                 System.out.println(new Date().getSeconds()+"  执行");
 9             }
10         }, date);
11     }
12 }

  这段代码的意思是,先建一个Timer,Timer开始执行的时间是” 2017-08-17 11:18:00”。

Timer重复执行

  上述代码Timer只会执行一次,如果我们想让定时任务每隔一段时间就执行呢?此时可以用Timer提供的schedule方法的另一个重载 public void schedule(TimerTask task, long delay, long period)。意思是Timer在delay的时候开始执行,每隔period时间长度执行一次。

 1 public class TimerTest {
 2 
 3     public static void main(String[] args) throws ParseException {
 4         Date date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-08-17 11:18:00");
 5         new Timer().schedule(new TimerTask() {
 6             @Override
 7             public void run() {
 8                 System.out.println(new Date().getSeconds()+"  执行");
 9             }
10         }, date,1000);
11     }
12 }

执行结果

  37  执行

  38  执行

  39  执行

  40  执行

  ……

Timer执行延时

  在执行TimerTask的时候可能会出现线程执行时间过长的情况,超过了Timer的等待时间。此时会是什么情况呢?

  

 1 public class TimerTest {
 2 
 3     public static void main(String[] args) throws ParseException {
 4         Date date=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-08-17 11:18:00");
 5         new Timer().schedule(new TimerTask() {
 6             @Override
 7             public void run() {
 8                 System.out.println(new Date().getSeconds()+"  开始执行");
 9                 try {
10                     Thread.sleep(2000);
11                     System.out.println(new Date().getSeconds()+"  执行结束");
12                 } catch (InterruptedException e) {
13                     e.printStackTrace();
14                 }
15             }
16         }, date,1000);
17     }
18 }

看执行结果

  0  开始执行

  2  执行结束

  2  开始执行

  4  执行结束

  4  开始执行

  6  执行结束

  6  开始执行

  8  执行结束

  8  开始执行

scheduleAtFixedRate

  使用schedule方法执行Timer任务,如果开始的时间是在当前时间之前,Timer并不会对之前没有执行的任务进行补充执行。也就是延时之后,那么Timer就从当前时间开始接着按照间隔时间执行。但是有时候我们的需求更加关注的执行的频率,需要把因为延时而导致没有执行的任务补充回来,此时就需要用到scheduleAtFiexdRate。

 1 public class TimerTest {
 2 
 3     public static void main(String[] args) throws ParseException {
 4         final Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-08-17 11:52:00");
 5         new Timer().scheduleAtFixedRate(new TimerTask() {
 6             @Override
 7             public void run() {
 8                 System.out.println(date);
 9                 System.out.println(new Date().getSeconds() + "  开始执行");
10                 System.out.println("执行了");
11                 System.out.println(new Date().getSeconds() + "  执行结束");
12 
13             }
14         }, date, 10000);
15     }
16 }

执行结果 

  39  开始执行

  执行了

  39  执行结束

  Thu Aug 17 11:52:00 CST 2017

  39  开始执行

  执行了

  39  执行结束

  Thu Aug 17 11:52:00 CST 2017

  40  开始执行

  执行了

  40  执行结束

 

  通过执行结果可以看出来,scheduleAtFixedRate上来就先将缺失的执行补上,然后再开始按照间隔时间一次一次执行。

将Timer设置成守护线程

 1 public class TimerTest {
 2 
 3     public static void main(String[] args) throws ParseException {
 4         final Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2017-08-17 11:52:00");
 5         Timer timer=new Timer();
 6         TimerTask timerTask= new TimerTask() {
 7             @Override
 8             public void run() {
 9                 System.out.println(date);
10                 System.out.println(new Date().getSeconds() + "  开始执行");
11                 System.out.println("执行了");
12                 System.out.println(new Date().getSeconds() + "  执行结束");
13 
14             }
15         };
16         timer.schedule(timerTask, date);
17     }
18 }

 

  在执行完代码之后,程序仍然在运行。看Timer.class的源代码可以发现Timer是创建了一个新的线程,而持续跟踪代码发现,新的线程进行了一个while(true)循环,再其中进入了等待状态。

1 public Timer(String name) {
2     thread.setName(name);
3     thread.start();
4 }

解决办法

  将Timer设置成守护线程,Timer有个构造函数。

1 public Timer(boolean isDaemon) {
2     this("Timer-" + serialNumber(), isDaemon);
3 }

  所以我们在将new Timer()改为new Timer(true)即可。

TimerTask和Timer的cancel方法 

  TimerTask的cancel方法是关闭这个任务,Timer的cancel方法是关闭整个Timer。

  Timer的执行实际上是启动了一个线程然后,线程中维护了一个队列,然后把TimerTask放入队列中。TimerTask的cancel方法就是将自身从任务队列中移除。Timer的cancel方法,是将队列中的任务全部清空。

posted @ 2017-08-17 15:37  一步一步学  阅读(856)  评论(1编辑  收藏  举报