美文网首页
线程保活

线程保活

作者: 奉灬孝 | 来源:发表于2020-04-16 00:13 被阅读0次

线程保活

当子线程中的任务执行完毕后,线程就被立刻销毁了。如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁线程,会造成资源的浪费。这时候我们就可以使用 RunLoop 来让该线程长时间存活而不被销毁。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    
    // 1.测试线程的销毁
    [self threadTest];
    
}
/**
 线程不保活
 */
- (void)threadTest
{
    NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(subThreadOpetion) object:nil];
    [subThread start];
}
/**
 子线程任务
 */
- (void)subThreadOpetion
{
    NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);
    NSLog(@"%@----子线程任务开始",[NSThread currentThread]);
    [NSThread sleepForTimeInterval:3.0];
    NSLog(@"%@----子线程任务结束",[NSThread currentThread]);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(subThreadOpetion) onThread:self.subThread withObject:nil waitUntilDone:NO];
}

当子线程中的任务执行完毕后,线程就被立刻销毁了。如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁线程,会造成资源的浪费。这时候我们就可以使用 RunLoop 来让该线程长时间存活而不被销毁。

/**
 线程保活
 */
- (void)threadTest
{
    NSThread *subThread = [[NSThread alloc] initWithTarget:self selector:@selector(subThreadEntryPoint) object:nil];
    [subThread setName:@"HLThread"];
    [subThread start];
    self.subThread = subThread;
}
/**
 子线程启动后,启动runloop
 */
- (void)subThreadEntryPoint
{
    @autoreleasepool {
        NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
        //如果注释了下面这一行,子线程中的任务并不能正常执行
        [runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
        NSLog(@"启动RunLoop前--%@",runLoop.currentMode);
        [runLoop run];
    }
}
/**
 子线程任务
 */
- (void)subThreadOpetion
{
    NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);
    NSLog(@"%@----子线程任务开始",[NSThread currentThread]);
    [NSThread sleepForTimeInterval:3.0];
    NSLog(@"%@----子线程任务结束",[NSThread currentThread]);
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(subThreadOpetion) onThread:self.subThread withObject:nil waitUntilDone:NO];
}

我们将上面的示例代码修改一下,修改后的代码过程为,创建一个子线程,当子线程启动后,启动 RunLoop,,RunLoop 添加了一个 NSMachPort ,这个 port 开启相当于添加了一个 Source1 事件源,但是这个事件源并没有真正的监听什么东西,只是为了不让 RunLoop 退出,从而达到了线程保活的目的。

RunLoop 启动前内部必须要有至少一个 Timer/Observer/Source,所以 AFNetworking【runLoop run】之前先创建了一个新的 NSMachPort 添加进去了。通常情况下,调用者需要持有这个 NSMachPort (mach_port)并在外部线程通过这个 port 发送消息到 loop 内;但此处添加 port只是为了让 RunLoop 不至于退出,并没有用于实际的发送消息。

RunLoop与线程

输出下边代码的执行顺序:

-(void)runloopEvent {
    NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"2");
        [self performSelector:@selector(test) withObject:nil afterDelay:10];
        NSLog(@"3");
    });
    NSLog(@"4");
   
}
-(void)test {
    NSLog(@"5");
}

答案是 1423,test 方法并不会执行。 原因是如果是带 afterDelay 的延时函数,会在内部创建一个 也就是如果当前线程没有开启 RunLoop,该方法会失效。 那么我们改成:

-(void)runloopEvent {
    NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    NSLog(@"2");
        [[NSRunLoop currentRunLoop]run];
        [self performSelector:@selector(test) withObject:nil afterDelay:10];
        NSLog(@"3");
    });
    NSLog(@"4");
   
}
-(void)test {
    NSLog(@"5");
}

然而 test 方法依然不执行。 原因是如果 RunLoopmode 中一个 item 都没有,RunLoop 会退出。即在调用 RunLoop 的 于其 mode 中没有添加任何 item 去维持 RunLoop 的时间循环,RunLoop 随即还是会退出。 所以我们自己启动 RunLoop,一定要在添加 item

-(void)runloopEvent {
    NSLog(@"1");
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        NSLog(@"2");
        [self performSelector:@selector(test) withObject:nil afterDelay:1];
        [[NSRunLoop currentRunLoop]run];
        NSLog(@"3");
    });
    NSLog(@"4");
}
-(void)test {
    NSLog(@"5");
}

这样就会输出14253

Demo:线程保活

相关文章

  • RunLoop -- 在实际开发中的应用

    1、控制线程生命周期<线程保活> 线程保活 2、解决NSTimer在滑动时失效的问题 当scrollView滑动的...

  • iOS底层原理——浅谈RunLoop

    RunLoop应用:线程保活 线程保活、控制销毁 iOS-浅谈RunLoop8iOS底层原理总结 - RunLoo...

  • iOS NSThread 保活线程代码封装

    iOS NSThread 保活线程代码封装

  • iOS Runloop的理解与使用

    Runloop的概念 Runloop的存在主要就是为了线程保活,线程保活是为了线程能够及时的处理事件,不会在其执行...

  • 线程保活

    在实际开发中,我们可能很多操作需要放在子线程中操作,可能会重复的创建线程。这个时候我们就需要创建一个线程并不让其销...

  • 线程保活

    线程保活是在多线程中进行耗时操作常用的功能: 常规开启方式,会出现内存泄漏 通过 [runloop run]直接...

  • 线程保活

    #import "ViewController.h" #import "WZJthread.h" @interfa...

  • 线程保活

    线程保活 当子线程中的任务执行完毕后,线程就被立刻销毁了。如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁...

  • 线程保活

    ViewController.h ViewController.m

  • iOS底层探索 --- RunLoop(实战)

    日常开发中我们常用的RunLoop场景有: 线程保活 Timer相关 APP卡顿检测 线程保活首先我们应该达成的共...

网友评论

      本文标题:线程保活

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