定时器

本文详细介绍了Java中的Timer类使用方法,包括如何实现延迟执行、周期性执行任务等,并深入解析了Timer构造函数及调度函数的工作原理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

(1)API使用

1.延迟x毫秒之后再执行制定代码

先new一个Timer对象,再调用schedule方法。

public void schedule(TimerTask task,long delay)
                 例子:
new Timer().schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println("this is a timer");
			}
		},3*1000);
结果:三秒之后打印this is a timer


2.延迟x毫秒之后执行,且第一次执行之后每隔y毫秒执行一次

public void schedule(TimerTask task,long delay,long period)
例子:

	new Timer().schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println(System.currentTimeMillis()+": " +"this is a timer");
			}
		},3*1000,2*1000);
  结果:

1415973070731: this is a timer
1415973072731: this is a timer
1415973074731: this is a timer
1415973076731: this is a timer


3.在指定时间执行

public void schedule(TimerTask task,Date time)
例子:

                Calendar calendar = Calendar.getInstance();
		calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
		
		new Timer().schedule(new TimerTask() {
			@Override
			public void run() {
				System.out.println(System.currentTimeMillis()+": " +"this is a timer");
			}
		},calendar.getTime());

4.在指定时间执行,并且第一次执行之后每隔period后执行一次

public void schedule(TimerTask task, Date firstTime, long period)
例子:

	public static void main(String[] args) 
	{
		Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
		Timer timer = new Timer();
		timer.schedule(new TimerTask() {
			
			@Override
			public void run() 
			{
				System.out.println(System.currentTimeMillis()+": " +"this is a timer");
			}
		}, calendar.getTime(), 5*1000);
	}
结果为:

1421988927613: this is a timer
1421988932613: this is a timer
1421988937613: this is a timer
1421988942614: this is a timer
1421988947618: this is a timer


               仔细观察上图,会发现并不是严格按照执行周期5s来执行的。实际上,该方法在计算下一次执行时间的时候,是通过在任务执行前得到的时间来计算的,例如设定是5s执行一次,那么理论上会在5,10,15,20这些时间之后执行,但是如果由于某些原因,CPU在第8s才调度线程,那么下一次执行就是13s,而不是理论上的第10s。

               那么如何让解决呢?可以使用scheduleAtFixedRate方法,也就是只算理论时间,如第8s被调度,那么计算出的下次执行时间就是按照理论上的精确时间来计算的,也就是第10s来执行


5.在指定时间执行,并且第一次执行之后每隔period后执行一次(按理论计算得来的时间)

	public static void main(String[] args) 
	{
		Calendar calendar = Calendar.getInstance();
                calendar.setTime(new Date(System.currentTimeMillis()+5*1000));
		Timer timer = new Timer();
		timer.scheduleAtFixedRate(new TimerTask() {
			
			@Override
			public void run() 
			{
				System.out.println(System.currentTimeMillis()+": " +"this is a timer");
			}
		}, calendar.getTime(), 5*1000);
	}
结果为:

1421989854378: this is a timer
1421989859378: this is a timer
1421989864378: this is a timer
1421989869379: this is a timer
1421989874381: this is a timer


(2)Timer构造函数分析

1.无参构造函数

    public Timer() 
    {
        this("Timer-" + serialNumber());
    }
      就是简单的为线程指定一个名字,前缀为Timer

2.为线程指定一个名字

    public Timer(String name) 
    {
        thread.setName(name);
        thread.start();
    }
3.定时器线程是否需要和进程的生命周期一样(如果一样,那么进程结束了定时器就会结束)
    public Timer(boolean isDaemon) 
    {
        this("Timer-" + serialNumber(), isDaemon);
    }


      注意到其中有一个thread,这个thread很明显是一个线程,被包装在了Timer类中,看下thread的定义:

    /**
     * The timer thread.
     */
    private final TimerThread thread = new TimerThread(queue);
      其中的TimerThread类定义为:

class TimerThread extends Thread {
     看到这里,就知道Timer内部封装了一个线程,用来做独立于外部线程的调度

     可以看到new TimerThread的时候传入了一个queue:

    private final TaskQueue queue = new TaskQueue();
     看名字就知道是一个队列,队列里面是要调度的任务

class TaskQueue {
    private TimerTask[] queue = new TimerTask[128];


(3)Timer调度函数分析

1.当前时间x毫秒后执行一次

    public void schedule(TimerTask task, long delay) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        sched(task, System.currentTimeMillis()+delay, 0);
    }
       这里调用了sched方法,将task传入,第一个参数传入System.currentTimeMillis()+delay可以看出第一次执行的时间点为当前时间推迟x毫秒,而这里第三个参数传入0,说明时间片为0,代表隔多久执行一次,0表示以后不执行


2.当前时间x毫秒后执行一次,以后每隔period毫秒执行一次

    public void schedule(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, -period);
    }
      这里period变为负数,只是理解不同,没有特别意义,可以忽略

3.当前时间x毫秒后执行一次,以后每隔period毫秒执行一次(按理论时间)

    public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
        if (delay < 0)
            throw new IllegalArgumentException("Negative delay.");
        if (period <= 0)
            throw new IllegalArgumentException("Non-positive period.");
        sched(task, System.currentTimeMillis()+delay, period);
    }
        唯一的区别就是period没有取反,作用也就是为了在sched中区别scheduleAtFixedRate和schedule

        下面来看下sched方法:

    private void sched(TimerTask task, long time, long period) 
    {
        if (time < 0)
            throw new IllegalArgumentException("Illegal execution time.");

        // Constrain value of period sufficiently to prevent numeric
        // overflow while still being effectively infinitely large.
        if (Math.abs(period) > (Long.MAX_VALUE >> 1))
            period >>= 1;

        synchronized(queue)
       {
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");

            synchronized(task.lock)
            {
                if (task.state != TimerTask.VIRGIN)
                    throw new IllegalStateException(
                        "Task already scheduled or cancelled");
                task.nextExecutionTime = time;
                task.period = period;
                task.state = TimerTask.SCHEDULED;
            }

            queue.add(task);
            if (queue.getMin() == task)
                queue.notify();
        }
    }



















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值