iOS中多线程实现方案

iOS中多线程实现方案

方案 简介 语言 生命周期 使用频率
pthread 通用多线程API
相信有其他语言开发经验的一定使用过
C 手动管理 几乎不用
NSThread OC中的线程对象 OC 手动管理 偶尔使用
GCD 能够充分利用设备的多核 C 自动管理 经常使用
NSOperation 基于GCD,使用更加的面向对象 OC 手动管理 经常使用

GCD的使用方法

简单来说GCD的使用就2个步骤

  1. 定制任务(需要执行的操作)
  2. 将任务添加到队列(用来存放任务,任务的执行遵循FIFO原则)

队列的类型

  1. 并发队列(允许多个任务并发执行,自动开启多个线程执行任务)

    • 全局并发队列
    • 手动创建
  2. 串行队列(任务串行执行,一个任务执行完后,再执行下一个任务)

    • 主队列(凡是添加到主队列中的任务都会放到主线程中执行)
    • 手动创建

GCD执行任务的常用函数

  1. 同步方式执行任务

    dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)

  2. 异步方式执行任务

    dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)

同步和异步的区别

同步:只能在当前线程中执行任务,不具备开启新线程的能力

异步:可以在新的线程中执行任务,具备开启新线程的能力

GCD执行任务的多种情况实例

使用异步方式创建任务,将任务放入串行队列中

- (void)asyncSerial{
    //创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("lcs", DISPATCH_QUEUE_SERIAL);

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

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
}

运行结果(开启一个新线程,串行执行)

 2016-04-09 13:35:30.409 GCD的使用[1473:29019]  {number = 1, name = main}
 2016-04-09 13:35:30.410 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  0
 2016-04-09 13:35:30.410 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  1
 2016-04-09 13:35:30.410 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  0
 2016-04-09 13:35:30.410 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  1
 2016-04-09 13:35:30.411 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  0
 2016-04-09 13:35:30.411 GCD的使用[1473:29101]  {number = 2, name = (null)} =======  1

使用异步方式创建任务,将任务放入主队列中

- (void)asyncMainQueue{

    //主队列 (加入到主队列中的任务,都在主线程执行)
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

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

    dispatch_async(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
}

运行结果(在主队列串行执行)

2016-04-09 14:24:25.509 GCD的使用[2171:53012] {number = 1, name = main}
2016-04-09 14:24:25.514 GCD的使用[2171:53012] {number = 1, name = main} ======= 0
2016-04-09 14:24:25.515 GCD的使用[2171:53012] {number = 1, name = main} ======= 1
2016-04-09 14:24:25.515 GCD的使用[2171:53012] {number = 1, name = main} ======= 0
2016-04-09 14:24:25.515 GCD的使用[2171:53012] {number = 1, name = main} ======= 1
2016-04-09 14:24:25.515 GCD的使用[2171:53012] {number = 1, name = main} ======= 0
2016-04-09 14:24:25.515 GCD的使用[2171:53012] {number = 1, name = main} ======= 1


使用异步方式创建任务,将任务放入并行队列中

- (void)asyncConcurrent{

    //自己创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("lcs", DISPATCH_QUEUE_CONCURRENT);

    //全局并发队列
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

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

    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });

    //async 异步函数,会等当前函数执行完后在开线程
    NSLog(@"asyncConcurrent");
}

运行结果(开启多个线程并行执行)

2016-04-09 14:47:17.777 GCD的使用[2533:62553] {number = 1, name = main}
2016-04-09 14:47:17.778 GCD的使用[2533:62553] asyncConcurrent
2016-04-09 14:47:17.778 GCD的使用[2533:62605] {number = 3, name = (null)} ======= 0
2016-04-09 14:47:17.778 GCD的使用[2533:62606] {number = 2, name = (null)} ======= 0
2016-04-09 14:47:17.778 GCD的使用[2533:62607] {number = 4, name = (null)} ======= 0
2016-04-09 14:47:17.779 GCD的使用[2533:62605] {number = 3, name = (null)} ======= 1
2016-04-09 14:47:17.779 GCD的使用[2533:62606] {number = 2, name = (null)} ======= 1
2016-04-09 14:47:17.779 GCD的使用[2533:62607] {number = 4, name = (null)} ======= 1


使用同步方式创建任务,将任务放入串行队列中

- (void)syncSerial{

    //自己创建并发队列
    dispatch_queue_t queue = dispatch_queue_create("lcs", DISPATCH_QUEUE_SERIAL);

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

    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(queue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });

    //sync  同步函数,会立刻加入到队列中执行
    NSLog(@"asyncConcurrent");

}

运行结果(在当前线程串行执行)

2016-04-09 14:49:48.982 GCD的使用[2577:64118] {number = 1, name = main}
2016-04-09 14:49:48.983 GCD的使用[2577:64118] {number = 1, name = main} ======= 0
2016-04-09 14:49:48.983 GCD的使用[2577:64118] {number = 1, name = main} ======= 1
2016-04-09 14:49:48.983 GCD的使用[2577:64118] {number = 1, name = main} ======= 0
2016-04-09 14:49:48.983 GCD的使用[2577:64118] {number = 1, name = main} ======= 1
2016-04-09 14:49:48.983 GCD的使用[2577:64118] {number = 1, name = main} ======= 0
2016-04-09 14:49:48.984 GCD的使用[2577:64118] {number = 1, name = main} ======= 1
2016-04-09 14:49:48.984 GCD的使用[2577:64118] asyncConcurrent


使用同步方式创建任务,将任务放入并行队列中

- (void)syncConcurrent{

    //全局并发队列
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    NSLog(@" %@", [NSThread currentThread]);

    dispatch_sync(globalQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(globalQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(globalQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    //sync  同步函数,会立刻加入到队列中执行
    NSLog(@"asyncConcurrent");
}

运行结果同上一种情况


使用同步方式创建任务,将任务放入主队列中

- (void)syncMainQueue{

    //主队列 (加入到主线程中的任务,都在主线程执行)
    dispatch_queue_t mainQueue = dispatch_get_main_queue();

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

    dispatch_sync(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
    dispatch_sync(mainQueue, ^{
        for (NSInteger i = 0; i < 2; i++) {
            NSLog(@" %@ =======  %ld", [NSThread currentThread], i);
        }
    });
}

运行结果(任务加入主队列造成互相等待,导致死锁)

2016-04-09 14:49:48.982 GCD的使用[2577:64118] {number = 1, name = main}


GCD多线程总结

方案 并发队列 手动创建串行队列 主队列
同步(sync) 没有开启新线程
串行执行
没有开启新线程
串行执行
没有开启新线程
串行执行
异步(async) 开启新线程
并行执行
开启新线程
串行执行
没有开启新线程
串行执行

NSOperation的使用方法

NSOperation的使用与GCD类似,它是个抽象类,必须使用它的子类,实现多线程操作

  • NSInvocationOperation
  • NSBlockOperation
  • 自定义类继承自NSOperation,并实现main方法

队列的类型

  1. 主队列(凡是添加到主队列中的任务都会放到主线程中执行)
  2. 手动创建队列(设置队列的最大并发数(maxConcurrentOperationCount)为1,则该队列为串行队列)

创建任务

- (void)viewDidLoad {
    [super viewDidLoad];

    //创建队列
    _queue = [[NSOperationQueue alloc] init];

    //设置最大并发数,设置为1,则该队列就是串行队列
    _queue.maxConcurrentOperationCount = 3;
}

- (void)createOperation{
    //创建任务
    //方式一
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];

    //方式二
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"messionBlock %@", [NSThread currentThread]);
    }];
    //添加额外的block
    [op2 addExecutionBlock:^{
        NSLog(@"messionExecution %@", [NSThread currentThread]);
    }];

    //方式三:自定义:(实现类的main方法)
    CSOperation *op3 = [[CSOperation alloc] init];

    //加入队列
    [_queue addOperation:op1]; //内部调用 [op1 start]
    [_queue addOperation:op2];
    [_queue addOperation:op3];
    [_queue addOperationWithBlock:^{
        NSLog(@"messionOperationWithBlock %@", [NSThread currentThread]);
    }];
}

- (void)run{
    for(int i = 0;i < 10; i++){
        NSLog(@"%d messionInvocation %@", i, [NSThread currentThread]);
    }

}

运行结果(开启多个线程,并行执行)

2016-04-16 17:40:23.640 NSOperation的使用[5589:149538] messionExecution {number = 5, name = (null)}
2016-04-16 17:40:23.640 NSOperation的使用[5589:149533] messionInvocation {number = 2, name = (null)}
2016-04-16 17:40:23.640 NSOperation的使用[5589:149532] messionmain {number = 3, name = (null)}
2016-04-16 17:40:23.642 NSOperation的使用[5589:149538] messionOperationWithBlock {number = 5, name = (null)}
2016-04-16 17:40:23.640 NSOperation的使用[5589:149531] messionBlock {number = 4, name = (null)}

设置任务之间的依赖,保证执行顺序(依赖设置可以跨队列操作)

- (void)addDependency{

    NSBlockOperation *b1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"b1");
    }];

    NSBlockOperation *b2 = [NSBlockOperation blockOperationWithBlock:^{
        for(int i = 0; i < 2; i++){
            NSLog(@"b2");
        }
    }];
    NSBlockOperation *b3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"b3");
    }];

    //监听线程执行完毕
    b3.completionBlock = ^{
        NSLog(@"b3 执行完毕 ---%@", [NSThread currentThread]);
    };

    //b3依赖于b1 b2
    [b3 addDependency:b1];
    [b3 addDependency:b2];

    [_queue addOperation:b1];
    [_queue addOperation:b2];
    [_queue addOperation:b3];

}

运行结果(b3等待b1,b2任务执行完后再执行)

2016-04-16 17:41:26.994 NSOperation的使用[5618:150401] b2
2016-04-16 17:41:26.994 NSOperation的使用[5618:150404] b1
2016-04-16 17:41:26.995 NSOperation的使用[5618:150401] b2
2016-04-16 17:41:26.996 NSOperation的使用[5618:150404] b3
2016-04-16 17:41:26.997 NSOperation的使用[5618:150408] b3 执行完毕 —{number = 2, name = (null)}

你可能感兴趣的:(iOS)