iOS多线程

iOS中多线程实现方案:

这里写图片描述

1.NSThread

1个NSThread对象就代表一条线程

创建线程:

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

启动线程:

[thread1 start];

2 GCD(Grand Central Dispatch)

1)为多核的并行运算提出解决方案。
2)会自动管理线程的生命周期(创建线程,调度线程,销毁线程)。
3)只需要告诉GCD想要执行什么任务,不需要编写任何线程管理的代码。

步骤:
1)定制任务
2)将任务放到队列中,GCD会自动将队列中的任务取出,放到对应的线程中执行。FIFO原则

GCD中有2个用来执行任务的函数:

1)同步方式(只能在当前的线路中执行任务,不具备开启新线程的能力)
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>);

2)异步方式(可以在新的线路中执行任务,具备开启新线程的能力)
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>);

GCD队列分为两大类:
1)并发队列(Concurrent Dispatch Queue)
可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
只有在异步方式“dispatch_async”下才有效。

2)串行队列(Serial Dispathc Queue)
让任务一个接一个的执行

// 1.获得全局的并发队列:
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// 并发队列可选择的优先级:
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
// 2.将任务加到队列中,异步方式执行(可创建子线程)
 dispatch_async(queue, ^{

        // 执行的任务

    });
// 创建串行队列
    dispatch_queue_t queue2 = dispatch_queue_create("name", NULL);
    // 非ARC需要手动释放
    dispatch_release(queue2);
// 获得主队列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

这里写图片描述

注意:使用sync向当前串行队列中添加任务,会卡住当前的串行队列。
因为当前任务或者方法已经在主队列中,在同步(sync)方式下,仍往该队列中添加任务,那么势必等当前方法执行完之后,才能执行新添加的任务,而新添加的任务不执行,当前方法也不会往下继续执行完。所以会卡住。

2.1 GCD进程间通讯:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

        // 子线程执行一些比较耗时的操作
        // ...

        dispatch_async(dispatch_get_main_queue(), ^{

            // 回到主线程,执行一些UI相关的操作
            // ...

        });
    });

2.2 利用GCD执行延迟操作:
不会卡住dispatch_after之后的操作,仍继续往下执行,等时间到了再回头执行里面的操作

   dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        // 操作...

    });

2.3 利用GCD控制代码执行的次数

  static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{

        // 只执行一次的操作
        // ...

    });

2.4 将读取/写入操作放到一个新建的串行队列中同步执行,可以代替同步锁,保证数据同步。

由于多个getter方法可以并发执行,而getter方法与setter方法间不能并发执行,利用这个特点,可以将读取和写入操作都放到一个“全局并发队列中”。

但是,为了保证并发队列中的读取/写入操作不是随时执行的,可以利用GCD的“barrier”功能。

在队列中,栅栏块必须单独执行,不能与其他块并行

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 虽然是并发队列,但“栅栏块”中的操作必须单独执行
    dispatch_barrier_sync(queue, ^{

        // 写入操作...
    });

3.NSOperation

NSOperation和NSOperationQueue实现多线程的步骤
1)先将需要执行的操作封装到一个NSOperation对象中
2)然后将NSOperation对象添加到NSOperationQueue中
3)系统会自动将NSOperationQueue中的NSOperation取出来
4)将取出的NSOperation封装的操作放到一条新线程中执行

  // 1.将操作封装到NSOperation对象中
NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{

        // 执行的操作...

    }]; 
[operation1 addExecutionBlock:^{
        // 执行完任务1后要执行的操作
    }];

  // 2.创建队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// NSOperationQueue *queue2 = [NSOperationQueue mainQueue];(主队列)

  // 3.添加操作到队列中   
[queue addOperation:operation1];

3.1设置最大并发数

queue.maxConcurrentOperationCount = 2;

3.2操作依赖关系
NSOperation之间可以设置依赖来保证执行次序
如:一定要当操作A完成之后才可以执行B操作

 NSBlockOperation *operationA = [NSBlockOperation blockOperationWithBlock:^{

        // A执行的操作...
    }];

    NSBlockOperation *operationB = [NSBlockOperation blockOperationWithBlock:^{

        // B执行的操作...
    }];

 // 操作B依赖于操作A
[operationB addDependency:operationA];

3.3取消队列的所有操作

[queue cancelAllOperations];

3.4暂停/恢复

-(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView
{
    // 开始拖拽时暂停/恢复操作
    [queue setSuspended:YES]; // or NO
}

使用NSOperation及NSOperationQueue的好处:
1)便于取消操作。在任务运行之前,可以在NSOperation对象上调用cancel方法,该方法会设置对象内的标志位,表明此任务不需要执行。

2)指定操作间的依赖关系。使特定的操作必须在另外一个操作顺利执行完后执行。

3)通过KVO监控NSOperation对象的属性,可以在某个任务变更其状态时得到通知。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值