线程中的Timer

作者: 楼上那位 | 来源:发表于2017-03-26 14:38 被阅读51次

突然有个疑问: 在一个子线程中启动一个timer,但是不添加到Runloop中,调用timer.fire(),这时候timer 会运行吗?

实践出真知 😝

   var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 20){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
        }

输出结果是:


1 false
2 false
repeating 2017-03-26 02:38:35 +0000 times = 1
2017-03-26 02:38:36 +0000
2017-03-26 02:38:36 +0000
3 false
<NSThread: 0x60000026f740>{number = 3, name = (null)}
<NSThread: 0x600000271b00>{number = 4, name = (null)}

在没有将timer add 到Runloop 中&& runloop 停止之前, timer 仅仅触发了一次执行操作。

WHY ?

到底这个timer 在线程中一直执行没有呢?很显然,他就执行一次(这与RunLoop 有何关系?)
那是不是Timer 执行完就被释放了呢,我们再看看3s 后 这个timer 是否还有效,times < 2, 添加3s 后检查timer.isvalide

  var  times = 1;
        let thread = Thread { 
            let   timer = Timer(timeInterval: 1, repeats: true, block: { (timer) in
                print("repeating \(Date.init()) times = \(times)")
                if(times < 2){
                    times += 1
                }else{
                    timer.invalidate()
                }
                
            })
            timer.fire()
            //RunLoop.current.add(timer, forMode: .defaultRunLoopMode)
            print(timer.fireDate)
            RunLoop.current.run(mode: .defaultRunLoopMode, before:Date(timeIntervalSinceNow: 10))// runloop运行后 在10s 后退出
             //RunLoop.current.run(until: Date.distantFuture)
            print(timer.fireDate)
            DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(3), execute: {
                print("after 3s  timer is running \(timer.isValid )")
            })
        }
        
        print("1 \(thread.isExecuting)")
        thread.start()
        print("2 \(thread.isExecuting)")
        let disTime = DispatchTime.now() + DispatchTimeInterval.seconds(4)
        DispatchQueue.global().asyncAfter(deadline:disTime) {
            print("3 \(thread.isExecuting)")
            print(thread)
            print(Thread.current)
            
        }
        
        

在看输出:


1 false
2 true
repeating 2017-03-26 03:01:41 +0000 times = 1
2017-03-26 03:01:42 +0000
2017-03-26 03:01:42 +0000
after 3s  timer is running true
3 false
<NSThread: 0x60000007f100>{number = 3, name = (null)}
<NSThread: 0x600000261900>{number = 4, name = (null)}

我认为 timer 就是一个线程,没有将其加入到Runloop ,该timer执行完他的代码就退出了。

可是线程要Runloop 干嘛呢?不是没有runLoop 线程也可以执行吗?确实是。
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出
RunLoop 存在的意义在于有如果我们需要随时处理事件并保持线程不退出

CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。

根据这个说法那就不难理解,如果不添加到Runloop ,Runloop 没有可接收的消息源,所在线程执行完后就退出。

一般滑动列表的时候我们还有一个timer 在运行,发现Timer 的回调不执行。原因有二

  1. 滑动列表是在TrackingMode,Timer 在defaultMode
  2. 同一时刻Runloop只对应一个Mode

从timer 的mode 切换到 trackingMode,Timer 的回调不执行,但是再次执行的时候会顺延至指定的间隔的整数倍(比如我们4:10 开启,每隔1m 调用一次,在4:12 切换到TrackingMode 4 m 后再切回来,那下次启动大概就是4:17 左右开始回调执行)

参考

Runloop的add 方法

func add(_ timer: Timer, forMode mode: RunLoopMode)
Description
Registers a given timer with a given input mode.
You can add a timer to multiple input modes. While running in the designated mode, the receiver causes the timer to fire on or after its scheduled fire date. Upon firing, the timer invokes its associated handler routine, which is a selector on a designated object.
The receiver retains aTimer. To remove a timer from all run loop modes on which it is installed, send an invalidate() message to the timer.

深入理解RunLoop

相关文章

  • 线程中的Timer

    突然有个疑问: 在一个子线程中启动一个timer,但是不添加到Runloop中,调用timer.fire(),这时...

  • GCD对timer的一种实现

    通常我们在主线程创建timer,此外,timer需要结合runloop才能实现。 如果有这样一个需求,在非主线程中...

  • 定时器之Timer

    概述 Timer 是可以指定将来的某个时间在后台线程中调度任务的工具。每个Timer对应一个后台线程用来顺序执行这...

  • Timer & TimerTask

    Timer Timer支持延迟任务和周期任务 Timer是一个线程,因此创建Timer开销还是比较大的 Timer...

  • Swift之延迟函数

    1.perform(必须在主线程中执行) 2.timer(必须在主线程中执行) 3.Thread (在主线程会卡主...

  • NStimer 和Runloop

    1、如果是在主线程中运行timer,想要timer在某界面有视图滚动时,依然能正常运转,那么将timer添加到Ru...

  • C# Timer 最简单形象的教程

    System.Threading.Timer System.Threading.Timer是使用多线程时间定时类:...

  • Android 定时器、定时任务整理

    1. ScheduledExecutorService Timer不支持多线程。全部挂在Timer下的任务都是单线...

  • springboot下使用定时任务的方式全揭秘

    1. 线程实现 利用线程可以设定休眠时间的方式可以实现简单的定时任务逻辑。 2. Timer类 Timer类允许调...

  • Timer 的简单使用

    Timer 的简单使用: 按照我的理解,Timer 相当于一个线程任务调度器,new 一个 Timer 并且设置...

网友评论

    本文标题:线程中的Timer

    本文链接:https://www.haomeiwen.com/subject/snnhottx.html