多线程应用:定时器

 一. 定时器

定时器(定时任务)

  • 定时器是一种控制任务延时调用,或者周期调用的技术。
  • 作用:闹钟、定时邮件发送。

定时器的实现方式

  • 方式一:Timer
  • 方式二:ScheduledExecutorService

二. Timer定时器

  • TimerTask继承了Runnable:所以TimerTask是线程任务类 

 

 2.1 Timer定时器的实现

package com.gch.d8_timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
   目标:Timer定时器的使用和了解
 */
public class TimerDemo1 {
    public static void main(String[] args) {
        // 1.创建Timer定时器
        Timer timer = new Timer(); // 定时器本身就是一个单线程。
        // 2.调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() { // 由定时器线程来调的
                System.out.println(Thread.currentThread().getName() + "执行一次!" 
+ new Date().toLocaleString());
            }  // 第一次执行 / 启动后首先延迟两秒执行,然后每隔三秒执行一次
        },2000,3000);
    }
}

 2.2 Timer定时器的特点和存在的问题

  1. 问题1:Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入
  • 因为Timer是单线程,某些任务忙,其他任务受到干扰,因为其他任务要等它处理完才执行,比如这里,A,B都是每隔两秒执行一次,但是执行到A的时候线程休眠了5秒,导致B已经过了2s的执行周期但因为线程在休眠无法执行,只能线程过了5s休眠才执行B
package com.gch.d8_timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
   目标:Timer定时器存在的问题
   问题1:Timer是单线程,处理多个任务按照顺序执行,存在延时与设置定时器的时间有出入
   因为Timer是单线程,某些任务忙,其他任务受到干扰,因为其他任务要等它处理完才执行
   比如这里,A,B都是每隔两秒执行一次,但是执行到A的时候线程休眠了5秒,导致B已经过了2s的执行周期但因为线程在休眠无法执行,只能线程过了5s休眠才执行B
 */
public class TimerDemo2 {
    public static void main(String[] args) {
        // 1.创建Timer定时器
        Timer timer = new Timer(); // 定时器本身就是一个单线程。
        // 2.调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行A!" + new Date().toLocaleString());
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            } // 启动后直接执行,然后每隔两秒执行一次
        },0,2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行B!" + new Date().toLocaleString());
            }
        },0,2000);
    }
}

问题二:可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行。

  • 比如这个程序要执行A,B,C三个任务,但是执行到B的时候程序出现异常,导致Timer线程直接挂掉,影响C的执行,导致整个任务全部挂掉。
package com.gch.d8_timer;

import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
   Timer定时器存在的问题
   问题二:可能因为其中的某个任务的异常使Timer线程死掉,从而影响后续任务执行。
   比如这个程序要执行A,B,C三个任务,但是执行到B的时候程序出现异常,导致Timer线程直接挂掉,影响C的执行
 */
public class TimerDemo3 {
    public static void main(String[] args) {
        // 1.创建Timer定时器
        Timer timer = new Timer(); // 定时器本身就是一个单线程。
        // 2.调用方法,处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行A!" + new Date().toLocaleString());
            } // 启动后直接执行,然后每隔两秒执行一次
        },0,2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行B!" + new Date().toLocaleString());
                System.out.println(10 / 0); // 出现算术异常,Timer线程直接挂掉,影响后续任务执行
            }
        },0,2000);

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行C!" + new Date().toLocaleString());
            }
        },0,3000);

    }
}

  •  结论:开发中一般不会去用Timer做定时器!

三. ScheduledExecutorService定时器

  • ScheduledExecutorService它可以用多个线程去处理多个任务,这样即使某一个线程挂掉了也不会影响其他线程的执行。
  • 线程池必然是高级的。

package com.gch.d8_timer;

import java.util.Date;
import java.util.TimerTask;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * 目标:ScheduledExecutorService定时器的了解与使用
 */
public class ScheduledExecutorServiceDemo4 {
    public static void main(String[] args) {
        // 1.创建ScheduledExecutorService线程池,做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

        // 2.开启定时任务
        // 以固定速率来执行
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出A   " + new Date().toLocaleString());
                try {
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },0,2000, TimeUnit.MILLISECONDS);

        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(10 / 0); // 有异常,B不执行
                System.out.println(Thread.currentThread().getName() + "执行输出B   " + new Date().toLocaleString());
            }
        },0,2000, TimeUnit.MILLISECONDS);


        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行输出C   " + new Date().toLocaleString());
            }
        },0,2000, TimeUnit.MILLISECONDS);
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Surpass余sheng军

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值