timer 订阅
Timer
信息
操作系统
未知
开发语言
开源协议
未知
Timer
Timer is an extension that is loosely based on Prototype's PeriodicalExecuter . The three main enhancements are: * It's for jQuery (1.1.x and 1.2.x) * Timer intervals can be reset during the event * It's a much shorter name
收起全文
精华内容
下载资源
问答
  • timer
    千次阅读
    2017-12-19 17:32:41

    Faster R-CNN中提供了一个很好用的python下计时工具,用于分析模型运行速度的评估。

    import time
    
    class Timer(object):
        """A simple timer."""
        def __init__(self):
            self.total_time = 0.
            self.calls = 0
            self.start_time = 0.
            self.diff = 0.
            self.average_time = 0.
    
        def tic(self):
            # using time.time instead of time.clock because time time.clock
            # does not normalize for multithreading
            self.start_time = time.time()
    
        def toc(self, average=True):
            self.diff = time.time() - self.start_time
            self.total_time += self.diff
            self.calls += 1
            self.average_time = self.total_time / self.calls
            if average:
                return self.average_time
            else:
                return self.diff

    使用时

    import Timer
    timer = Timer()
    timer.tic() # 单次开始计时
    ...
    timer.toc() # 结束本次计时,返回值可以为多次的平均时间, 也可以为此次时间差toc(average=False)

    注意:

    计算机系统存在两个时间:CPU时间time.clock(),挂钟时间time.time()

    • CPU时间>挂钟时间: 计算密集型任务,通过优化程序并发可以获得更好的效果,包含CPU内核调度时间(sys)和CPU计算时间(user)
    • 挂钟时间≈CPU时间: IO密集型任务,不能通过并发改进性能,

    具体使用参考: Python程序计时

    更多相关内容
  • apb总线timer的verilog

    2018-10-24 11:18:00
    是基于apb总线下的timer外设的rtl代码,主要包括apb_timer的master逻辑verilog,以及相应的开发文档,包括寄存器的描述,功能特性等。
  • 最新单片机仿真 TIMER0与TIMER1控制条形LED最新单片机仿真 TIMER0与TIMER1控制条形LED最新单片机仿真 TIMER0与TIMER1控制条形LED最新单片机仿真 TIMER0与TIMER1控制条形LED最新单片机仿真 TIMER0与TIMER1控制条形LED...
  • 定时器Timer

    万次阅读 多人点赞 2020-10-20 11:11:29
    定时器Timer 为什么要使用定时器呢? 比如说一个web应用,如果这个应用规模很大,那它的日志数据是不是很多。如果一直存下来服务器的存储量怕是不行吧,需要隔一段时间删除,那么就需要一个线程每隔一段时间去...

    #定时器Timer

    为什么要使用定时器呢?

    比如说一个web应用,如果这个应用规模很大,那它的日志数据是不是很多。如果一直存下来服务器的存储量怕是不行吧,需要隔一段时间删除,那么就需要一个线程每隔一段时间去删除日志数据。

    直接来个程序:

    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TestTimer {
    public static void main(String[] args) {
        Timer timer=new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("我执行了"+"  "+System.currentTimeMillis());
            }
        },1000,2000);
    }
    }
    

    运行结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ym8DcEmP-1603163485909)(https://i.imgur.com/f5551y1.png)]

    Timer 是调度器,TimerTask 调度任务。


    ##Timer类

    ###构造方法

    Timer() 创建一个新的计时器。

    Timer(boolean isDaemon) 创建一个新的定时器,其相关线程可以指定为 run as a daemon 。

    Timer(String name) 创建一个新的定时器,其相关线程具有指定的名称。

    Timer(String name, boolean isDaemon) 创建一个新的定时器,其相关线程具有指定的名称,可以指定为 run as a daemon 。

    若指定为守护进程有什么效果呢?

    //将上面程序的new Timer时候传入参数true
    Timer timer=new Timer(true);
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8Bduindu-1603163485911)(https://i.imgur.com/fVjH9hl.png)]

    因为是守护进程,main线程结束,所以不会执行直接结束。

    ###方法

    void cancel() 终止此计时器,丢弃任何当前计划的任务,将任务队列中的全部任务清空。

    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TestTimer {
    public static void main(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("我执行了" + "  " + System.currentTimeMillis());
            }
        }, 1000, 2000);
    
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        timer.cancel();
    
    }
    }
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-POqEAnyC-1603163485913)(https://i.imgur.com/zFGIz4S.png)]


    TimerTask类中的cancel()方法将自身从任务队列中清除。

    	final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        TimerTask timerTaskTwo = new TimerTask() {
            @Override
            public void run() {
                System.out.println("Two运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask,1000,2000);
        timer.schedule(timerTaskTwo,1000,2000);
        try {
            Thread.sleep(6000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        timerTaskTwo.cancel();
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKFbh4ZE-1603163485914)(https://i.imgur.com/bhVJWyD.png)]


    void schedule(TimerTask task, Date time) 在指定的时间安排指定的任务执行。

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TestTimer {
    public static void main(String[] args) throws ParseException {
        final Timer timer = new Timer();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //时间已经过去
        String dateString = "2018-06-19 21:19:00";
        String dateStringTwo = "2018-06-19 21:28:00";
        Date date = dateFormat.parse(dateString);
        Date dateTwo = dateFormat.parse(dateStringTwo);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        TimerTask timerTaskTwo = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask, date);
        timer.schedule(timerTaskTwo, dateTwo);
    
    }
    }
    

    结果:
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tBqCpxMZ-1603163485915)(https://i.imgur.com/45AwwmH.png)]

    已经过去的时间一运行就执行任务,而未到达的时间等到达后执行任务。

    为什么程序执行完还不结束?

    这是因为系统默认当 Timer 运行结束后,如果没有手动终止,那么则只有当系统的垃圾收集被调用的时候才会对其进行回收终止。或调用 Timer 类自带的 cancel() 方法,实现 Timer 的终止。


    void schedule(TimerTask task, Date firstTime, long period)从指定的时间开始 ,对指定的任务执行重复的 固定延迟执行 。

    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.Timer;
    import java.util.TimerTask;
    
    public class TestTimer {
    public static void main(String[] args) throws ParseException {
        final Timer timer = new Timer();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //时间已经过去
        String dateString = "2018-06-19 21:44:40";
        Date date = dateFormat.parse(dateString);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask, date,2000);
    
    }
    }
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HxiRSy7C-1603163485916)(https://i.imgur.com/dkgaGhK.png)]


    void schedule(TimerTask task, long delay) 在指定的延迟之后安排指定的任务执行。

    	final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask, 2000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xUfxUwXe-1603163485917)(https://i.imgur.com/R4pUZ9z.png)]


    void schedule(TimerTask task, long delay, long period) 在指定的延迟之后开始 ,重新执行固定延迟执行的指定任务。

    	final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask, 3000,2000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ax2hsuTe-1603163485918)(https://i.imgur.com/7K7V4a6.png)]


    void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) 从指定的时间开始 ,对指定的任务执行重复的固定速率执行 。

        final Timer timer = new Timer();
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        //时间已经过去
        String dateString = "2018-06-19 21:44:40";
        Date date = dateFormat.parse(dateString);
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        //timer.schedule(timerTask, date,2000);
        timer.scheduleAtFixedRate(timerTask, date,2000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-JM5fW488-1603163485918)(https://i.imgur.com/4xecFcR.png)]

    之前未执行的任务都被执行了。

    改为

    timer.schedule(timerTask, date,2000);
    //timer.scheduleAtFixedRate(timerTask, date,2000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FOjdBDf4-1603163485919)(https://i.imgur.com/Vsy5G1Z.png)]
    之前未执行的任务都被没有被执行。


    void scheduleAtFixedRate(TimerTask task, long delay, long period) 在指定的延迟之后开始 ,重新执行固定速率的指定任务。

    	final Timer timer = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("运行了,现在" + new Date());
            }
        };
        timer.scheduleAtFixedRate(timerTask, 3000,2000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VBC7FoLQ-1603163485920)(https://i.imgur.com/3kiRXfl.png)]


    ##源码探索

    若创建了无参对象 new Timer() ,查看 Timer 无参构造器:

    public Timer() {
        this("Timer-" + serialNumber());
    }
    

    这边调用 Timer(String name) 构造器,查看 serialNumber() 方法

    /**
     * This ID is used to generate thread names.
     */
    //初始化从 0 开始
    private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
    private static int serialNumber() {
    	//返回值后加 1
        return nextSerialNumber.getAndIncrement();
    }
    

    验证:

     	Timer timer = new Timer();
        Timer timerTwo = new Timer();
        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                System.out.println("运行了,现在" + new Date());
            }
        };
        TimerTask timerTaskTwo = new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
                System.out.println("Two运行了,现在" + new Date());
            }
        };
        timer.schedule(timerTask, 1000);
        timerTwo.schedule(timerTaskTwo, 1000);
    

    结果:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M9Wp6fHk-1603163485920)(https://i.imgur.com/ZxKsUBX.png)]

    查看 Timer(String name)

    public Timer(String name) {
        thread.setName(name);
        thread.start();
    }
    

    查看 thread

    private final TaskQueue queue = new TaskQueue();
    
    private final TimerThread thread = new TimerThread(queue);
    

    TaskQueue 任务队列用来存放任务即TimerTask,thread来跑任务。


    ###查看 TimerThread 类

    boolean newTasksMayBeScheduled = true;
    

    newTasksMayBeScheduled 用于控制当queue任务队列为空时,定时线程是否应该立刻终止(false立刻终止)

    private TaskQueue queue;
    

    queue 任务队列。

    public void run() {
        try {
    		//最核心
            mainLoop();
        } finally {
            // Someone killed this Thread, behave as if Timer cancelled
            synchronized(queue) {
                newTasksMayBeScheduled = false;
                queue.clear();  // Eliminate obsolete references
            }
        }
    }
    

    最核心

    private void mainLoop() {
        while (true) {
            try {
                TimerTask task;
                boolean taskFired;
    			// 获取任务队列的锁
                synchronized(queue) {
    				// 如果任务队列为空,并且线程没有被cancel()
                	// 则线程等待queue锁,queue.wait()方法会释放获得的queue锁
                	// 这样在Timer中sched()方法才能够获取到queue锁
                    while (queue.isEmpty() && newTasksMayBeScheduled)
                        queue.wait();
                    if (queue.isEmpty())
                        break; // Queue is empty and will forever remain; die
    
                    // Queue nonempty; look at first evt and do the right thing
                    long currentTime, executionTime;
                    task = queue.getMin();
                    synchronized(task.lock) {
                        if (task.state == TimerTask.CANCELLED) {
                            queue.removeMin();
                            continue;  // No action required, poll queue again
                        }
                        currentTime = System.currentTimeMillis();
                        executionTime = task.nextExecutionTime;
                        if (taskFired = (executionTime<=currentTime)) {
    						// 任务应该被触发,并且不是重复任务
                        	// 将任务从队列中移除并修改任务的执行状态
                            if (task.period == 0) { // Non-repeating, remove
                                queue.removeMin();
                                task.state = TimerTask.EXECUTED;
                            } else { 
    							// 任务是重复执行任务,计算任务下一次应该被执行的时间,并重新排序任务队列
                                queue.rescheduleMin(
                                  task.period<0 ? currentTime   - task.period
                                                : executionTime + task.period);
                            }
                        }
                    }
                    if (!taskFired) // Task hasn't yet fired; wait
                        queue.wait(executionTime - currentTime);
                }
                if (taskFired)  // Task fired; run it, holding no locks
                    task.run();
            } catch(InterruptedException e) {
            }
        }
    }
    

    到这里你会发现为什么正常情况下Timer运行完任务后一直不结束因为一直是while(true) 除非遇到不能捕获的异常或break才会跳出。

    if (queue.isEmpty())
        break;
    

    如果是设置了newTasksMayBeScheduled状态为false跳出,也就是调用了cancel,那么queue就是空的,此时就直接跳出外部的死循环,所以cancel就是这样实现的。


    Timer类中sched方法

    下面所有的 schedule 方法都调用了sched方法

    void schedule(TimerTask task, long delay)

    void schedule(TimerTask task, Date time)

    void schedule(TimerTask task, long delay, long period)

    void schedule(TimerTask task, Date firstTime, long period)

    void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

    void scheduleAtFixedRate(TimerTask task, long delay, long period)

    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) {
    		//判断Timer是否已经取消
            if (!thread.newTasksMayBeScheduled)
                throw new IllegalStateException("Timer already cancelled.");
    
            synchronized(task.lock) {
    			//TimerTask.VIRGIN标记任务没有被调度
                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();
        }
    }
    

    为什么要做notify操作呢?

    因为mainLoop()里面的wait()。


    Timer类中cancel方法

    public void cancel() {
        synchronized(queue) {
            thread.newTasksMayBeScheduled = false;
            queue.clear();
            queue.notify();  // In case queue was already empty.
        }
    }
    

    修改newTasksMayBeScheduled为false,删除queue队列中的任务


    ###查看TaskQueue类

    private TimerTask[] queue = new TimerTask[128];
    

    TimerTask数组,初始数组大小为128。

    int size() {
        return size;
    }
    

    size()任务队列的长度

     void add(TimerTask task) {
        // Grow backing store if necessary
        if (size + 1 == queue.length)
    		//扩2倍长度
            queue = Arrays.copyOf(queue, 2*queue.length);
    
        queue[++size] = task;
        fixUp(size);
    }
    

    add(TimerTaskt)为增加一个任务

    TimerTask getMin() {
        return queue[1];
    }
    

    getMin()获取当前排序后最近需要执行的一个任务,下标为1,队列头部0是不做任何操作的

     TimerTask get(int i) {
        return queue[i];
    }
    

    get(int i)获取指定下标的数据,当然包括下标 0

    void removeMin() {
        queue[1] = queue[size];
        queue[size--] = null;  // Drop extra reference to prevent memory leak
        fixDown(1);
    }
    

    removeMin()为删除当前最近执行的任务,也就是第一个元素,通常只调度一次的任务,在执行完后,调用此方法,就可以将TimerTask从队列中移除。

    void quickRemove(int i) {
        assert i <= size;
    
        queue[i] = queue[size];
        queue[size--] = null;  // Drop extra ref to prevent memory leak
    }
    

    quickRmove(int i) 删除指定的元素,一般来说是不会调用这个方法的,这个方法只有在 Timer 发生 purge 的时候,并且当对应的 TimerTask调用了 cancel 方法的时候,才会被调用这个方法,也就是取消某个TimerTask,然后就会从队列中移除(注意如果任务在执行中是,还是仍然在执行中的,虽然在队列中被移除了),还有就是这个 cancel 方法并不是 Timer 的 cancel 方法而是 TimerTask,一个是调度器的,一个是单个任务的,最后注意,这个 quickRmove 完成后,是将队列最后一个元素补充到这个位置,所以此时会造成顺序不一致的问题,后面会有方法进行回补。

    void rescheduleMin(long newTime) {
        queue[1].nextExecutionTime = newTime;
        fixDown(1);
    }
    

    rescheduleMin(long newTime)是重新设置当前执行的任务的下一次执行时间,并在队列中将其从新排序到合适的位置,而调用的是后面说的fixDown方法。

    boolean isEmpty() {
        return size==0;
    }
    

    isEmpty() 判空。

    void clear() {
        // Null out task references to prevent memory leak
        for (int i=1; i<=size; i++)
            queue[i] = null;
    
        size = 0;
    }
    

    clear() 清理。

    对于 fixUp(int k) 和 fixDown(int k) 方法来讲,前者是当新增一个task的时候,首先将元素放在队列的尾部,然后向前找是否有比自己还要晚执行的任务,如果有,就将两个任务的顺序进行交换一下。而fixDown正好相反,执行完第一个任务后,需要加上一个时间片得到下一次执行时间,从而需要将其顺序与后面的任务进行对比下。

    heapify(),其实就是将队列的后半截,全部做一次fixeDown的操作,这个操作主要是为了回补quickRemove方法,当大量的quickRmove后,顺序被打乱后,此时将一半的区域做一次非常简单的排序即可。


    ###TimerTask抽象类

    //对象锁
    final Object lock = new Object();
    
    //task状态初始VIRGIN
    int state = VIRGIN;
    
    //这项任务尚未安排好
    static final int VIRGIN = 0;
    
    //这个任务计划执行。如果它是一个非重复的任务,那么它还没有被执行
    static final int SCHEDULED   = 1;
    
    //此非重复任务已经执行(或目前正在执行)并没有被取消。
    static final int EXECUTED    = 2;
    
    //此任务被取消了
    static final int CANCELLED   = 3;
    
    //任务下次执行时间
    long nextExecutionTime;
    
    //重复任务的周期(毫秒)。一个积极的值表示固定利率执行。负值表示固定延迟执行。值为0表示非重复任务。
    long period = 0;
    
    //取消任务
    public boolean cancel()
    
    //计划执行时间
    public long scheduledExecutionTime() {
        synchronized(lock) {
            return (period < 0 ? nextExecutionTime + period
                               : nextExecutionTime - period);
        }
    }
    

    #总结

    参考
    Java多线程编程核心技术
    https://blog.csdn.net/xieyuooo/article/details/8607220
    https://www.jianshu.com/p/58a5b0853451

    Timer类其实内部有个thread,还有一个queue(来存储task),task会按一定的方式将任务排队处理,thread中的run方法无限循环task队列,执行task中的run()。

    才学疏浅,有什么问题请大家指出来。十分感谢!

    展开全文
  • Java定时器(Timer

    万次阅读 2021-06-19 16:48:42
    Timer和TimerTask是用于在后台线程中调度任务的java util类。简单地说,TimerTask是要执行的任务,Timer是调度器。 2.调度一次性任务 2.1 指定延迟后执行 让我们从简单地在定时器的帮助下运行单个任务开始: @Test ...

    1.介绍

    Timer和TimerTask是用于在后台线程中调度任务的java util类。简单地说,TimerTask是要执行的任务,Timer是调度器。

    2.调度一次性任务

    2.1 指定延迟后执行

    让我们从简单地在定时器的帮助下运行单个任务开始:

    @Test
    public void givenUsingTimer_whenSchedulingTaskOnce_thenCorrect() {
        TimerTask task = new TimerTask() {
            public void run() {
                System.out.println("Task performed on: " + new Date() + "n" +
                  "Thread's name: " + Thread.currentThread().getName());
            }
        };
        Timer timer = new Timer("Timer");
        
        long delay = 1000L;
        timer.schedule(task, delay);
    }
    

    延迟时间作为schedule()方法的第二个参数给出。我们将在下一节中了解如何在给定的日期和时间执行任务。

    注意,如果我们正在运行这是一个JUnit测试,我们应该添加一个Thread.sleep(delay*2)调用,以允许定时器的线程在JUnit测试停止执行之前运行任务。

    2.2 指定时间执行

    现在,让我们看看Timer#schedule(TimerTask,Date)方法,它将日期而不是long作为其第二个参数,这实现了在某个时刻而不是在延迟之后执行任务。

    这一次,让我们假设我们有一个旧的遗留数据库,我们希望将它的数据迁移到一个具有更好模式的新数据库中。我们可以创建一个DatabaseMigrationTask类来处理该迁移:

    public class DatabaseMigrationTask extends TimerTask {
        private List<String> oldDatabase;
        private List<String> newDatabase;
    
        public DatabaseMigrationTask(List<String> oldDatabase, List<String> newDatabase) {
            this.oldDatabase = oldDatabase;
            this.newDatabase = newDatabase;
        }
    
        @Override
        public void run() {
            newDatabase.addAll(oldDatabase);
        }
    }
    

    为简单起见,我们用字符串列表来表示这两个数据库。简单地说,我们的迁移就是将第一个列表中的数据放到第二个列表中。要在所需的时刻执行此迁移,我们必须使用schedule()方法的重载版本:

    List<String> oldDatabase = Arrays.asList("Harrison Ford", "Carrie Fisher", "Mark Hamill");
    List<String> newDatabase = new ArrayList<>();
    
    LocalDateTime twoSecondsLater = LocalDateTime.now().plusSeconds(2);
    Date twoSecondsLaterAsDate = Date.from(twoSecondsLater.atZone(ZoneId.systemDefault()).toInstant());
    
    new Timer().schedule(new DatabaseMigrationTask(oldDatabase, newDatabase), twoSecondsLaterAsDate);
    

    我们将迁移任务和执行日期赋予schedule()方法。然后,在twoSecondsLater指示的时间执行迁移:

    while (LocalDateTime.now().isBefore(twoSecondsLater)) {
        assertThat(newDatabase).isEmpty();
        Thread.sleep(500);
    }
    assertThat(newDatabase).containsExactlyElementsOf(oldDatabase);
    

    虽然我们在这一刻之前,迁移并没有发生。

    3.调度一个可重复执行任务

    既然我们已经讨论了如何安排任务的单个执行,那么让我们看看如何处理可重复的任务。同样,Timer类提供了多种可能性:我们可以将重复设置为观察固定延迟或固定频率。

    • 固定延迟:意味着执行将在最后一次执行开始后的一段时间内开始,即使它被延迟(因此它本身被延迟)。假设我们想每两秒钟安排一个任务,第一次执行需要一秒钟,第二次执行需要两秒钟,但是延迟了一秒钟。然后,第三次执行将从第五秒开始:

    • 固定频率:意味着每次执行都将遵守初始计划,无论之前的执行是否被延迟。让我们重用前面的示例,使用固定的频率,第二个任务将在3秒钟后开始(因为延迟)。但是,四秒钟后的第三次执行(关于每两秒钟执行一次的初始计划):

    关于这两种调度方式,让我们看看如何使用它们:

    为了使用固定延迟调度,schedule()方法还有两个重载,每个重载都使用一个额外的参数来表示以毫秒为单位的周期性。为什么两次重载?因为仍然有可能在某个时刻或某个延迟之后开始执行任务。

    至于固定频率调度,我们有两个scheduleAtFixedRate()方法,它们的周期也是以毫秒为单位的。同样,我们有一种方法可以在给定的日期和时间启动任务,还有一种方法可以在给定的延迟后启动任务。

    注意一点:如果一个任务的执行时间超过了执行周期,那么无论我们使用固定延迟还是固定速率,它都会延迟整个执行链。

    3.1 固定延迟

    现在,让我们设想一下,我们要实现一个通讯系统,每周向我们的追随者发送一封电子邮件。在这种情况下,重复性任务似乎是理想的。所以,让我们安排每秒钟的通讯,这基本上是垃圾邮件,但由于发送是假的,所以不用在意:)

    让我们首先设计一个任务:

    public class NewsletterTask extends TimerTask {
        @Override
        public void run() {
            System.out.println("Email sent at: " 
              + LocalDateTime.ofInstant(Instant.ofEpochMilli(scheduledExecutionTime()), 
              ZoneId.systemDefault()));
        }
    }
    

    每次执行时,任务都会打印其调度时间,我们使用TimerTask#scheduledExecutionTime()方法收集这些时间。那么,如果我们想在固定延迟模式下每秒钟安排一次这个任务呢?我们必须使用前面提到的schedule()的重载版本:

    new Timer().schedule(new NewsletterTask(), 0, 1000);
    
    for (int i = 0; i < 3; i++) {
        Thread.sleep(1000);
    }
    

    当然,我们只对少数情况进行测试:

    Email sent at: 2020-01-01T10:50:30.860
    Email sent at: 2020-01-01T10:50:31.860
    Email sent at: 2020-01-01T10:50:32.861
    Email sent at: 2020-01-01T10:50:33.861

    如上所示,每次执行之间至少有一秒钟的间隔,但有时会延迟一毫秒。这种现象是由于我们决定使用固定延迟重复。

    3.3 调度一个每日任务

    @Test
    public void givenUsingTimer_whenSchedulingDailyTask_thenCorrect() {
        TimerTask repeatedTask = new TimerTask() {
            public void run() {
                System.out.println("Task performed on " + new Date());
            }
        };
        Timer timer = new Timer("Timer");
        
        long delay = 1000L;
        long period = 1000L * 60L * 60L * 24L;
        timer.scheduleAtFixedRate(repeatedTask, delay, period);
    }
    

    4.取消调度器和任务

    4.1 在Run方法中去掉调度任务

    在run()方法对TimerTask本身的实现中调用TimerTask.cancel()方法:

    @Test
    public void givenUsingTimer_whenCancelingTimerTask_thenCorrect()
      throws InterruptedException {
        TimerTask task = new TimerTask() {
            public void run() {
                System.out.println("Task performed on " + new Date());
                cancel();
            }
        };
        Timer timer = new Timer("Timer");
        
        timer.scheduleAtFixedRate(task, 1000L, 1000L);
        
        Thread.sleep(1000L * 2);
    }
    

    4.2 取消定时器

    调用Timer.cancel()方法:

    @Test
    public void givenUsingTimer_whenCancelingTimer_thenCorrect() 
      throws InterruptedException {
        TimerTask task = new TimerTask() {
            public void run() {
                System.out.println("Task performed on " + new Date());
            }
        };
        Timer timer = new Timer("Timer");
        
        timer.scheduleAtFixedRate(task, 1000L, 1000L);
        
        Thread.sleep(1000L * 2); 
        timer.cancel(); 
    }
    

    5.Timer对比ExecutorService

    我们也可以使用ExecutorService来安排定时器任务,而不是使用定时器。下面是一个在指定间隔运行重复任务的快速示例:

    @Test
    public void givenUsingExecutorService_whenSchedulingRepeatedTask_thenCorrect() 
      throws InterruptedException {
        TimerTask repeatedTask = new TimerTask() {
            public void run() {
                System.out.println("Task performed on " + new Date());
            }
        };
        ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
        long delay  = 1000L;
        long period = 1000L;
        executor.scheduleAtFixedRate(repeatedTask, delay, period, TimeUnit.MILLISECONDS);
        Thread.sleep(delay + period * 3);
        executor.shutdown();
    }
    

    那么定时器和ExecutorService解决方案之间的主要区别是什么:

    • 定时器对系统时钟的变化敏感;ScheduledThreadPoolExecutor并不会。
    • 定时器只有一个执行线程;ScheduledThreadPoolExecutor可以配置任意数量的线程。
    • TimerTask中抛出的运行时异常会杀死线程,因此后续的计划任务不会继续运行;使用ScheduledThreadExecutor–当前任务将被取消,但其余任务将继续运行。

    6.本文代码

    Java定时器样例代码

    展开全文
  • init_timer(timer):初始化timer。 setup_timer(timer, fn, data):与init_timer()类似,fn为定时器回调函数,data为回调函数的参数。 void add_timer(struct timer_list *timer) 用于向 Linux 内核注册定时器,使用...

    一、内核定时器API函数

    init_timer(timer):初始化timer。

    setup_timer(timer, fn, data):与init_timer()类似,fn为定时器回调函数,data为回调函数的参数。

    void add_timer(struct timer_list *timer)
    用于向 Linux 内核注册定时器,使用 add_timer 函数向内核注册定时器以后,定时器就会开始运行。

    int mod_timer(struct timer_list *timer, unsigned long expires)
    用于修改定时值,如果定时器还没有激活的话, mod_timer 函数会激活定时器。
    timer:要修改超时时间的定时器。
    expires:修改后的超时时间。
    返回值: 0,调用 mod_timer 函数前定时器未被激活; 1,调用 mod_timer 函数前定时器已被激活。

    del_timer(struct timer_list * timer)
    用于删除一个定时器,不管定时器有没有被激活,都可以使用此函数删除。

    上面定义的timer为timer_list结构体,结构体定义如下:

    struct timer_list {
    	/*
    	 * All fields that change during normal runtime grouped to the
    	 * same cacheline
    	 */
    	struct hlist_node	entry;
    	unsigned long		expires;
    	void			(*function)(unsigned long);
    	unsigned long		data;
    	u32			flags;
    
    #ifdef CONFIG_TIMER_STATS
    	int			start_pid;
    	void			*start_site;
    	char			start_comm[16];
    #endif
    #ifdef CONFIG_LOCKDEP
    	struct lockdep_map	lockdep_map;
    #endif
    };
    

    /* by 面朝大海0902 */

    二、内核定时器使用方法

    struct timer_list timer; /* 定义定时器 */
    
    /* 定时器回调函数 */
    void function(unsigned long arg)
    {
    /*
    * 定时器处理代码
    */
    
    /* 如果需要定时器周期性运行的话就使用 mod_timer
    * 函数重新设置超时值并且启动定时器。
    */
    mod_timer(&dev->timertest, jiffies + msecs_to_jiffies(2000));
    }
    
    /* 初始化函数 */
    void init(void)
    {
    init_timer(&timer); /* 初始化定时器 */
    
    timer.function = function; /* 设置定时处理函数 */
    timer.expires=jffies + msecs_to_jiffies(2000);/* 超时时间 2 秒 */
    timer.data = (unsigned long)&dev; /* 将设备结构体作为参数 */
    
    /*上面也可以用setup_timer()函数*/
    
    add_timer(&timer); /* 启动定时器 */
    }
    
    /* 退出函数 */
    void exit(void)
    {
    del_timer(&timer); /* 删除定时器 */
    /* 或者使用 */
    del_timer_sync(&timer);
    }
    

    此处参考《【正点原子】I.MX6U嵌入式Linux驱动开发指南》

    三、驱动使用实例

    /* by 面朝大海0902 */

    #include <linux/module.h>
    #include <linux/poll.h>
    
    #include <linux/fs.h>
    #include <linux/errno.h>
    #include <linux/miscdevice.h>
    #include <linux/kernel.h>
    #include <linux/major.h>
    #include <linux/mutex.h>
    #include <linux/proc_fs.h>
    #include <linux/seq_file.h>
    #include <linux/stat.h>
    #include <linux/init.h>
    #include <linux/device.h>
    #include <linux/tty.h>
    #include <linux/kmod.h>
    #include <linux/gfp.h>
    #include <linux/gpio/consumer.h>
    #include <linux/platform_device.h>
    #include <linux/of_gpio.h>
    #include <linux/of_irq.h>
    #include <linux/interrupt.h>
    #include <linux/irq.h>
    #include <linux/slab.h>
    #include <linux/fcntl.h>
    #include <linux/timer.h>
    
    struct gpio_key{
    	int gpio;
    	struct gpio_desc *gpiod;
    	int flag;
    	int irq;
    };
    
    static struct gpio_key *ptr_gpio_key;
    
    static int major =0;
    static struct class *key_class;
    static int g_key_value = 0;
    struct fasync_struct *key_fasync;
    
    /* 环形缓冲区 */
    #define BUF_LEN 128
    static int g_keys[BUF_LEN];
    static int r, w;
    
    #define NEXT_POS(x) ((x+1) % BUF_LEN)
    
    static int is_key_buf_empty(void)
    {
    	return (r == w);
    }
    
    static int is_key_buf_full(void)
    {
    	return (r == NEXT_POS(w));
    }
    
    static void put_key(int key)
    {
    	if (!is_key_buf_full())
    	{
    		g_keys[w] = key;
    		w = NEXT_POS(w);
    	}
    }
    
    static int get_key(void)
    {
    	int key = 0;
    	if (!is_key_buf_empty())
    	{
    		key = g_keys[r];
    		r = NEXT_POS(r);
    	}
    	return key;
    }
    
    static DECLARE_WAIT_QUEUE_HEAD(key_wait);
    struct timer_list key_timer;
    
    void timer_function(unsigned long arg)
    {
    	int value;
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	struct gpio_key *ptr_gpio_key_temp = arg;
    	value = gpiod_get_value(ptr_gpio_key_temp->gpiod);
    	g_key_value = (ptr_gpio_key_temp->gpio << 8) | value;
    	printk(KERN_INFO "g_key_value is %d \r\n", g_key_value);
    	put_key(g_key_value);
    	wake_up_interruptible(&key_wait);
    	kill_fasync(&key_fasync, SIGIO, POLLIN);
    }
    
    static int key_drv_read(struct file *file, char __user *buf, size_t size, loff_t *offset)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	wait_event_interruptible(key_wait, !is_key_buf_empty());
    	g_key_value = get_key();
    	copy_to_user(buf, &g_key_value, 4);
    	return 4;
    }
    
    /* by 面朝大海0902 */
    static unsigned int key_drv_poll(struct file *fp, poll_table * wait)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	poll_wait(fp, &key_wait, wait);//非阻塞函数
    	
    	return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
    }
    
    static int key_drv_fasync(int fd, struct file *file, int on)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	if(fasync_helper(fd, file, on, &key_fasync) >= 0)
    		return 0;
    	else
    		return -EIO;
    }
    
    static struct file_operations key_drv =
    {
    	.owner = THIS_MODULE,
    	.read  = key_drv_read,
    	.poll  = key_drv_poll,
    	.fasync = key_drv_fasync,
    };
    
    static irqreturn_t gpio_key_isr(int irq, void *dev_id)
    {
    	key_timer.data =(unsigned long) dev_id;
    	mod_timer(&key_timer, jiffies + HZ/4);
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	return IRQ_HANDLED;
    }
    /* by 面朝大海0902 */
    static int key_probe(struct platform_device *pdev)
    {
    	int count = 0;
    	int i=0;
    	enum of_gpio_flags flag;
    	struct device_node *node = pdev->dev.of_node;
    	
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	count = of_gpio_count(node);
    	ptr_gpio_key = kzalloc(sizeof(struct gpio_key)*count, GFP_KERNEL);
    	
    	for(i=0;i<count;i++)
    	{
    		ptr_gpio_key[i].gpio = of_get_gpio_flags(node, i, &flag);
    		if(ptr_gpio_key[i].gpio < 0)
    		{
    			printk(KERN_ERR "of_get_gpio_flags is err\r\n");
    		}
    		ptr_gpio_key[i].gpiod = gpio_to_desc(ptr_gpio_key[i].gpio);
    		ptr_gpio_key[i].flag = flag & OF_GPIO_ACTIVE_LOW;
    		ptr_gpio_key[i].irq = gpio_to_irq(ptr_gpio_key[i].gpio);
    		request_irq(ptr_gpio_key[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "gpio_key", &ptr_gpio_key[i]);
    	}
    	
    	major = register_chrdev(0, "my_keydrv", &key_drv);
    	key_class = class_create(THIS_MODULE, "my_key_class");
    	if(IS_ERR(key_class))
    	{
    		printk(KERN_ERR "class_create is err\r\n");
    	}
    	
    	device_create(key_class, NULL, MKDEV(major, 0), NULL, "my_key%d", 0);
    	init_timer(&key_timer);
    	key_timer.function = timer_function;
    	key_timer.expires = ~0;
    	add_timer(&key_timer);
    
    	return 0;	
    }
    /* by 面朝大海0902 */
    
    static int key_remove(struct platform_device *pdev)
    {
    	int count = 0;
    	int i = 0;
    	struct device_node *node = pdev->dev.of_node;
    
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	count = of_gpio_count(node);
    
    	device_destroy(key_class, MKDEV(major, 0));
    	class_destroy(key_class);
    	unregister_chrdev(major, "my_keydrv");
    	for(i=0;i<count;i++)
    	{
    		free_irq(ptr_gpio_key[i].irq, &ptr_gpio_key[i]);
    	}
    
    	kfree(ptr_gpio_key);
    	del_timer(&key_timer);
    
    	return 0;	
    }
    
    
    static const struct of_device_id my_key[] =
    {
    	{.compatible = "my,key_driver"},
    	{},
    };
    
    
    static struct platform_driver key_driver =
    {
    	.probe  = key_probe,
    	.remove = key_remove,
    	.driver = 
    	{
    		.name = "key_gpio",
    		.of_match_table = my_key,
    	},
    };
    
    
    static int __init my_key_init(void)
    {
    	int result;
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	result = platform_driver_register(&key_driver);
    	return result;
    }
    /* by 面朝大海0902 */
    
    static void __exit my_key_exit(void)
    {
    	printk(KERN_INFO "%s %s line is %d \r\n", __FILE__, __FUNCTION__, __LINE__);
    	platform_driver_unregister(&key_driver);
    }
    
    module_init(my_key_init);
    module_exit(my_key_exit);
    
    MODULE_LICENSE("GPL");
    

    上面的程序比较啰嗦,大家捡重点看,参照内核定时器的使用方法,重点关注定时器几个API函数如何使用就可以,程序主要是在按键按下后启动250ms的定时器以去抖后读取按键电平值。程序也是在上一节Linux异步通知—fasync_helper()、kill_fasync()函数介绍与使用,驱动的基础上进行修改的,有兴趣的可以参考下。

    四、实验结果

    运行读取key值的应用(应用程序源码参考Linux异步通知—signal()、fcntl()函数介绍与使用),2个按键分别按下打印如下:

    [root@:/mnt]# ./key-fasync-test /dev/my_key0
    [  348.849247] /home/book/code/test/key-timer.c key_drv_fasync line is 115
    by mianchaodahai 0902
    [  353.465002] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  353.497099] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  353.754661] /home/book/code/test/key-timer.c timer_function line is 85
    [  353.761511] g_key_value is 33025
    [  353.766473] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x8101
    by mianchaodahai 0902
    [  356.423750] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  356.674635] /home/book/code/test/key-timer.c timer_function line is 85
    [  356.681481] g_key_value is 33024
    [  356.685883] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x8100
    by mianchaodahai 0902
    [  356.696007] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  356.954636] /home/book/code/test/key-timer.c timer_function line is 85
    [  356.961483] g_key_value is 33025
    [  356.965885] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x8101
    by mianchaodahai 0902
    [  358.266013] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  358.524630] /home/book/code/test/key-timer.c timer_function line is 85
    [  358.531524] g_key_value is 33024
    [  358.536222] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x8100
    by mianchaodahai 0902
    [  359.783520] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  360.034661] /home/book/code/test/key-timer.c timer_function line is 85
    [  360.041512] g_key_value is 33025
    [  360.045921] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x8101
    by mianchaodahai 0902
    [  363.732414] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  363.984584] /home/book/code/test/key-timer.c timer_function line is 85
    [  363.991372] g_key_value is 28160
    [  363.995392] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x6e00
    by mianchaodahai 0902
    [  365.786148] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  366.044637] /home/book/code/test/key-timer.c timer_function line is 85
    [  366.051484] g_key_value is 28161
    [  366.055900] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x6e01
    by mianchaodahai 0902
    [  367.154126] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  367.404645] /home/book/code/test/key-timer.c timer_function line is 85
    [  367.411495] g_key_value is 28160
    [  367.415914] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x6e00
    by mianchaodahai 0902
    [  368.834009] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  368.840782] /home/book/code/test/key-timer.c gpio_key_isr line is 134
    [  369.094551] /home/book/code/test/key-timer.c timer_function line is 85
    [  369.101311] g_key_value is 28161
    [  369.105202] /home/book/code/test/key-timer.c key_drv_read line is 97
    get button : 0x6e01
    by mianchaodahai 0902
    ^C[  370.907659] /home/book/code/test/key-timer.c key_drv_fasync line is 115
    
    

    可以看到按键按下后先触发中断回调函数gpio_key_isr(),间隔250ms左右(我们设置的超时时间一致)定时器回调函数timer_function()被调用。
    /* by 面朝大海0902 */

    这个示例代码可以学习内核定时器的相关使用,大家有兴趣也可以看下应用层定时器的使用Linux应用层定时器timer使用—timerfd_create()、timerfd_settime()、timerfd_gettime()

    展开全文
  • HarmonyOS实战——TickTimer定时器组件基本使用

    千次阅读 多人点赞 2021-09-09 15:07:21
    TickTimer定时器组件说明: 是Text的子类,所以可以使用Text的一些属性 该组件目前有一些bug,后续版本中会修复这些bug的 bug汇总: 不要用 setBaseTimer 去设置基准时间。 停止之后不用重新开始。 常见属性: ...
  • Java 定时器Timer

    千次阅读 2022-04-06 11:49:25
    Timer是Java提供的原生Scheduler(任务调度)工具类,用来在一个后台线程计划执行指定任务。 利用Timer可以安排任务“执行一次”或者定期“执行多次”。 Timer类提供了以下方法: schedule(TimerTask task, Date time...
  • Timer定时器用法详解

    万次阅读 多人点赞 2019-07-06 17:30:20
    Timer timer = new Timer(); //其中会调用this("Timer-" + serialNumber());, 即它以Timer+序列号为该定时器的名字 Timer timer = new Timer(String name); //以name作为该定时器的名字 Timer time...
  • Timer详解

    千次阅读 2019-07-03 12:16:35
    文章目录timer介绍:timer的使用:timer源码分析:生产者代码消费者代码timer的schedule和scheduleAtFixedRate区别:timer的缺点:timer的替代产品: timer介绍: Timer是Josh Bloch在jdk1.3发布的一个新的api,...
  • Linux时间子系统之定时器层(Timer

    千次阅读 2020-05-08 16:13:33
    定时器层是基于Tick层之上...struct timer_list { /* * All fields that change during normal runtime grouped to the * same cacheline */ struct hlist_node entry; unsigned long expires; void (...
  • Unity 计时器 Timer 实现

    千次阅读 2022-04-13 20:01:13
    这里写自定义目录标题Timer类构建TimerManeger构建 实现了基本的计时、暂停、停止功能 支持最多三参数函数触发 未实现帧计时功能 Timer类构建 using System; using UnityEngine; public class Timer { public bool...
  • Threadx 定时器timer

    千次阅读 2020-02-08 23:02:58
    Threadx 操作系统定时器提供单次定时和周期性定时功能...定时时间长度用时钟节拍个数衡量,比如时钟节拍为5ms,应用程序设置定时时间为1.5s,那么1.5s/5ms=300,调用_tx_timer_create创建定时器时,定时器值设置为30...
  • Arduino定时器配置(Timer0,Timer1,Timer2)

    千次阅读 2020-12-19 19:48:29
    一、Arduino定时器简介 Arduino UNO有三个定时器,分别是timer0,timer1和timer2。每个定时器都有一个计数器,在计时器的每个时钟周期递增。当计数器达到存储在比较匹配寄存器中指定值时触发CTC定时器中断。一旦...
  • GD32450i-EVAL学习笔记 8 - Timer & PWM

    千次阅读 2021-06-13 11:07:41
    GD32F450最多有14组Timer,这些定时器分成5种类型。
  • iOS Swift Timer的销毁问题以及优化

    千次阅读 2022-03-26 16:49:46
    最近在同事的代码里看到了一些定时器使用上的问题,其实Timer虽然用起来看似很简单,但是稍不注意就会出现问题,造成一些偶发性的崩溃。 下面这个是常见的写法,看似没问题,其实deinit方法是不会被调用的,Timer...
  • Android定时器Timer简单使用

    千次阅读 2021-10-25 09:45:33
    Android定时器Timer简单使用Timer简介Timer使用总结 Timer简介 Timer(计时器)位于 java.util包下,可用于创建定时任务,任务可以安排为一次性执行,也可以定期重复执行。每个计时器对象对应一个后台线程...
  • Godot Timer节点

    千次阅读 2022-03-24 16:06:05
    文章目录1.Timer——在其他语言中的含义2.Timer——在Godot的含义3.常用调整4.实际分析Timer节点在FlappyBird中的游戏设计理念5.在FlappyBird中的游戏设计操作6.附脚本内容 博客的参考资料,是来自 开发游戏的老王的...
  • System.Timers.Timer与System.Threading.Timer

    千次阅读 2020-01-12 16:10:31
    我最近一直在查看一些可能的计时器,而Threading.Timer和Timers.Timer对我来说是必要的(因为它们支持线程池)。 我正在制作游戏,我计划使用不同类型的活动,间隔不同等。
  • 7. 补充设定 timer1 定时器和 timer2 定时器定时做多件事(教程) 原文地址:https://www.arduino.cn/thread-12452-1-1.html 下面仅仅是将原文给编辑一下,原文阅读有困难,看原文时一定看看下面的评论。 前面跟大家...
  • 7 Timer1简介Timer即定时器,与SysTick定时器不同的是,并非ARM Cortex-M3/M4处理器都有,而是某一些开发板特有的,且数量和类别存在一定差别。GD32450i-EVAL开发板共有14个定时器,分别为TIMER0-TIMER13,其中有2个...
  • vb6_高精度Timer控件

    热门讨论 2012-10-10 09:28:53
    QueryPerformanceCounter写的Timer控件,功能与vb6自带Timer基本一致,毫秒级精度
  • c中timer的用法

    千次阅读 2021-05-23 08:25:28
    c中timer的用法的用法你知道吗?下面小编就跟你们详细介绍下c中timer的用法的用法,希望对你们有用。c中timer的用法的用法如下:关于C#中timer类 在C#里关于定时器类就有3个1.定义在System.Windows.Forms里2.定义在...
  • Flink源码解析系列--Timer定时器

    千次阅读 2022-03-26 16:41:23
    Timer(定时器)是 Flink Streaming API 提供的用于感知并利用 Processing Time/Event Time 变化的机制。Ververica blog上给出的描述如下: Timers are what make Flink streaming applications reactive and ...
  • 使用 MsTimer2 库

    万次阅读 多人点赞 2019-04-12 15:33:32
    ARDUINO TIMER AND INTERRUPT TUTORIAL:...3. 使用 MsTimer2 库定时做多件事(教程)(定时器timer2的使用) 转载:使用 MsTimer2 库定时做多件事(教程)(定时器timer2的使用) https: //www.arduino...
  • 本文将阐述Timer、DispatchSourceTimer、CADisplayLink三种定时器的创建使用、注意事项,以及各自的优缺点。
  • Matlab中Timer的使用

    千次阅读 2021-01-26 15:48:09
    鉴于Matlab 中缺乏多线程机制,使用Timer 无疑是一个很重要的工具,Matlab 中Timer 是一个Java 对象。 (1) Timer 的定义 t=timer(); 设置属性: eg. set(t,‘Name’,‘your_timer_name’); 当然可以一次性设置完成: ...
  • 31 TIMER0与TIMER1控制条形LED.zip
  • Timer简介 Timer(定时器)是Flink Streaming API提供的用于感知并利用处理时间/事件时间变化的机制。Ververica blog上给出的描述如下: Timers are what make Flink streaming applications reactive and ...
  • arch_timer驱动分析

    千次阅读 2019-11-06 16:23:05
    arch_timer的初始化 static void __init arch_timer_common_init(void) { arch_timer_banner(arch_timers_present);//打印计时器的信息 arch_counter_register(arch_timers_present);//注册计数器 arch_timer_...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 484,771
精华内容 193,908
关键字:

timer