美文网首页
iOS 多线程

iOS 多线程

作者: 欧辰_OSR | 来源:发表于2022-07-06 11:08 被阅读0次

    在iOS 中实现多线程的方案:

    ·Pthreads

    ·NSThread

    ·GCD

    ·NSOperation & NSOperationQueue

    Pthreads

    这个基于c语言的框架,所以能够跨平台,在类Unix操作系统(Unix、Linux、Mac OS X等)中,都使用Pthreads作为操作系统的线程。

    OC 代码中的使用

    先得导入头文件 

    #import <pthread.h>

    创建一个线程,并且执行任务

    - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {      

        pthread_t thread;

        //创建一个线程并自动执行 

        pthread_create(&thread, NULL, start, NULL);

     } 

    void *start(void *data) { 

         NSLog(@"%@", [NSThread currentThread]); return NULL;

     } 

    打印结果:

     <NSThread: 0x6000020957c0>{number = 3, name = (null)}

    pthread 是语言的函数还得手动管理生命周期,手动销毁。对于习惯了ARC的我们真的很不爽。

    NSThread

    这种方式是苹果封装的,完全面向对象。所以使用的时候可直接操作对象,很直观、方便。就是需要我们手动的去管理生命周期。所以 只是 [NSThread currentThread]  用来获取当前的线程类,查看当前线程的属性,调试起来还比较方便,以下下是一些用法。

    创建并启动

    · 先创建线程,再启动

    // 创建 

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

    // 启动

     [thread start];

    · 创建线程并启动

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

    · 使用 NSObject 的方法创建并自动启动

    [self performSelectorInBackground:@selector(run:) withObject:nil];

    NSThread的一些其他方法

    //取消线程   

     - (void)cancel; 

    //启动线程

     - (void)start; 

    //判断某个线程的状态的属性 

    @property (readonly, getter=isExecuting) BOOL executing;

     @property (readonly, getter=isFinished) BOOL finished;

     @property (readonly, getter=isCancelled) BOOL cancelled; 

    //设置和获取线程名字 

    -(void)setName:(NSString *)n; 

    -(NSString *)name;

     //获取当前线程信息 

    + (NSThread *)currentThread; 

    //获取主线程信息 

    + (NSThread *)mainThread; 

     //使当前线程暂停一段时间,或者暂停到某个时刻 

    + (void)sleepForTimeInterval:(NSTimeInterval)time;

    + (void)sleepUntilDate:(NSDate *)date;  

    GCD

    提高cpu的利用率,自动管理线程的生命周期,block 回调方式使用方便。

    任务和队列

    在GCD中,的任务和队列

    任务:即操作,在GCD中就是一个Block,所以添加任务十分方便。任务有两种执行方式:同步执行和异步执行,他们之间的区别是 是否创建新的线程。

    同步执行:只要是同步执行的任务,都会在当前线程执行,不会另开辟线程。

    异步执行:只要是异步执行的任务,都会另开辟线程,在别的线程执行。

    更新:

    这里说的并不准确,同步(sync)和异步(async)的主要区别在于会不会阻塞主线程,直到Block中的任务执行完毕!

    如果是同步(sync)操作,它会阻塞当前线程并等待Block中的任务执行完毕,然后当前线程才会继续往下运行。

    如果是异步(async)操作,当前线程会直接往下执行,它不会阻塞当前线程。

    ·队列:用于存放任务。一共有两种队列。串行队列和并行队列。

    串行队列中的任务会根据队列的定义FIFO的执行,一个接一个的先进先出的进行执行。

    重新:放到串行队列的任务,GCD会FIFO(先进先出)地取出来一个,执行一个,然后取下一个,这样一个一个的执行。

    并行队列中的任务 根据同步或者异步有不同的执行方式。

    更新:放到并存队列的任务,GCD也会FIFO的取出来,但不同的是,他取出来一个就会放到别的线程,然后再取出一个放到另一个线程。这样由于取的动作很快忽略不计,看起来,所有的任务都是一起执行的。不过需要注意,GCD会根基系统资源控制并行的数量,所以如果任务很多,它并不会让所有任务同时执行。

    总结下表

    同步执行 异步执行

    串行队列当前线程,一个一个执行其他线程,一个一个执行

    并行队列当前线程,一个一个执行开很多线程,一起执行

    创建队列

    主队列:这是一个特殊的  串行队列。主队列 用来刷新UI。任何需要刷新UI的工作多需要主队列执行,所以一般耗时的任务都要放到别的线程执行。

    //OBJECTIVE-C

    dispatch_queue_t queue = ispatch_get_main_queue();

    自己创建的队列:凡是自己创建的队列都是串行队列。

    更新:自己可以创建串行队列,也可以创建 并行队列。看下面的代码(代码已更新),它有两个参数,第一个上面已经说了,第二个才是最重要的。第二个参数用来表示创建的队列是串行还是并行的。传入 DISPATCH_QUEUE_SERIAL 或NULL表示创建串行队列。传入DISPATCH_QUEUE_CONCURRENT 表示创建并行队列。

    //OBJECTIVE-C

    串行队列

    dispatch_queue_tqueue= dispatch_queue_create("tk.bourne.testQueue",NULL); 

    dispatch_queue_tqueue= dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_SERIAL);

     //并行队列 

    dispatch_queue_tqueue= dispatch_queue_create("tk.bourne.testQueue", DISPATCH_QUEUE_CONCURRENT);

    全局并行队列:这应该是唯一一个并行队列,要是并行任务一般都加入到这个队列。这是系统提供的一个并发队列。

    //OBJECTIVE-C 

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    创建任务

    同步任务: 不会另开线程 改:会阻塞当前线程 (SYNC)

    OBJECTIVE-C

    dispatch_sync(<#queue#>, ^{ 

        //code here NSLog(@"%@", [NSThread currentThread]); 

    });

    异步任务:会另开线程 改:不会阻塞当前线程 (ASYNC)

    OBJECTIVE-C

    dispatch_async(<#queue#>, ^{ 

        //code here NSLog(@"%@", [NSThread currentThread]); 

    });

    更新

    为了更好的理解同步和异步,和各种队列的使用,下面看两个示例:

    示例一:

    以下代码在主线程调用,结果是什么?

    NSLog("之前 - %@", NSThread.currentThread())

    dispatch_sync(dispatch_get_main_queue(), { () -> Void in

         NSLog("sync - %@", NSThread.currentThread())

     }) 

    NSLog("之后 - %@", NSThread.currentThread())

    答案:

    只会打印第一句:之前 - <NSThread: 0x7fb3a9e16470>{number = 1, name = main} ,然后主线程就卡死了,你可以在界面上放一个按钮,你就会发现点不了了。

    解释:

    同步线程会阻塞当前的线程,然后把Block中的任务放到指定的队列中执行,只能等到Block中的任务完成后才能让当前线程继续往下运行。

    那么这里的步聚就是:打印完第一步后,dispatch_sync立即阻塞当前的主线程,然后把Block中的任务放到main_queue中,可是main_queue中的任务会被取出来放到主线程中执行,但主线程这个时候已经被阻塞了,所以block中的任务就不能完成,它不完成,dispatch_sync就会一直阻塞主线程,  就不能完成,他不完成,dispatch_sync 就会一直阻塞主线程,

    相关文章

      网友评论

          本文标题:iOS 多线程

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