• iOS学习——多线程开发(NSThread)


      具体来说,iOS方面多线程也就是两种,pthread以及NSThread。pthread是C语言写的多线程,好处是不仅仅用在iOS移动端开发,基本上支持C语言的都可以使用,缺点就是C语言的共性了,不易识别,难记而且并不支持arc。所以在iOS中多线程开发还是去了解NSThread更好,pthread掌握即可。

      在oc对象的使用中,最为常见的就是alloc与init,对象内存分配和实例化。所以就有可能出现这种情况:

        NSThread *thread1 = [[NSThread alloc] init];

        [thread1 start];

      实际上这是不行的,NSThread无法直接alloc init,但是可以派生子类来实例化。要使用线程对象,可以通过这种方式:

     NSThread *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(runThread) object:nil];

        [thread2 start];

    当然如果不想使用对象方式开启线程,有更简便的方式:

        [NSThread detachNewThreadSelector:@selector(runThread) toTarget:self withObject:nil];

    当然,这种方式就没办法使用线程的一些属性了。可以用thread2.name 来给线程自定义一个名字,这样当出现线程崩溃的情况,可以在左边的崩溃列表直接定位到是哪个线程出现了问题。另外可以通过threadPriority来设置线程的优先级,不过设置优先级仅仅增加了线程的被调用概率,而不是完全先调用优先级高的线程。

    可以看到,虽然优先调用了thread2,但是其中仍然穿插了thread3的调用。(在多线程开发中,不要相信一次或者少数次运行结果);

      线程的状态包括五种,nsthread可以帮我们管理其中的四种,一种是在线程池中创建一个线程,第二种是[thread start],这并不是直接开启线程,而是让线程进入准备状态,runloop可以随时调用,第三种就是runing 了,这个是我们无法控制的,第四个是sleep状态或者叫阻塞状态,当线程运行完或我们调用sleep就会进行这种状态,第五种就是dead 了,可以通过exit来杀死线程。

      进一步学习,我们使用线程是用来干什么的呢?当然是耗时操作不方便放在主线程种调用。那么我们处理完数据后,还是要去修改UI,难道是直接修改就可以了?当然不是,iOSUI使用都是在主线程中,所有就有了线程间通讯技术使用,保证安全准确更新UI

    - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;

    第一个SEL是在主线程种执行的方法,第二个arg是需要传入的参数,第三个wait是表示当前线程是否等待,如果为YES,那么只有等待sel方法执行完了,线程才会继续进行。

    在子线程中,或许你可以更新UI成功,但是这会出现很多不确定性问题,譬如你今天运行OK,明天再次运行就会挂了,让你完全摸不着头脑。

    提到上面这个方法,就必定了解到另外一个

        [self performSelector:@selector(othreRunThread) onThread:thread2 withObject:nil waitUntilDone:NO];

     

    你会发现,当你提交函数进入thread2中,函数并没有被执行。这就涉及到runloop,runloop会开启一个死循环,让线程的执行形成一个圆,当执行完毕就会从头开始再次执行,不断循环询问系统是否有方法需要执行,我们开启的子线程并没有加入循环中,就像一条线,它已经走到了底部,你再在线的起点加入函数,线程也不会回头去执行。我们可以在线程中使用实现runloop

    - (void)runThread{

        [[NSRunLoop currentRunLoop] run];

        

            NSLog(@"------%@,%@-------",NSStringFromSelector(_cmd),[NSThread currentThread]);

    }

    不过这并不是一个很好的选择,这样会开启一个始终占用资源的死循环线程,我们并没有很好的办法去停止这个循环。

    - (void)runThread{

        while (!self.isfinshed) {

            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.1f]];

        }

            NSLog(@"------%@,%@-------",NSStringFromSelector(_cmd),[NSThread currentThread]);

    }

    - (void)othreRunThread{

        self.finshed = YES;

            NSLog(@"------%@,%@-------",NSStringFromSelector(_cmd),[NSThread currentThread]);

    }

    我们可以用一个全局的判断条件来进行设置,当othreRunThread未被执行的时候,我们就开启循环0.1秒,不断的让线程去询问是否有方法未被执行,当方法已经执行后,就不再进行循环。

      最后我们得知道,cpu仅能同时处理一条线程,多线程并发并不是多条线程同时进行,而是cpu不断在线程间切换进行,所以线程并不是越多越好,当存在大量线程,会让cpu在切换间疲于奔命,反而不利于开发。而setStackSize则可以主动分配一个线程所占内存大小,让线程运行更加合理。

  • 相关阅读:
    世界企业家:创业者需知的8条创业逻辑
    比尔·盖茨的“机会”观——不追求机会,才会有机会
    我爱思佳(帮别人名字作诗)
    唐艺铭(帮别人名字作诗)
    我爱思佳(帮别人名字再作诗)
    优秀是一种习惯:智者五句话足以改变你的人生
    别了,我的情人
    李丽萍(帮别人名字作诗)
    Know GCS AND GES structure size in shared pool
    测试Exadata单个cell失败
  • 原文地址:https://www.cnblogs.com/zhulilove/p/7805725.html
Copyright © 2020-2023  润新知