iOS学习----------多线程(NSThread/GCD/NSOperation)

本文主要介绍iOS中多线程的实现方案,本文需要有iOS基础的同学观看,如果有什么问题欢迎留言联系。
iOS中多线程的实现方案有4中,如图:
这里写图片描述
上图简单明了的介绍了4种方式的优缺点,下面我们主要从第二种方式NSThread开始。
1、NSThread
(1)创建线程的方式有三种

    /*
        1、需要手动开启线程
        开启了子线程
     */
    NSThread *firstThread = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@[@"firstThread"]];
    //线程开始(需要手动开启)
    firstThread.name = @"first";
    [firstThread start];

        /*
     2、不需要手动开启线程
        开启了子线程
    */
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"secondThread"];
    /*
        3、隐市创建方式
        开启子线程
     */
    [self performSelectorInBackground:@selector(run:) withObject:@[@"performSelectorInBackground"]];

三种方式的运行结果

2016-03-04 10:48:56.373 多线程demo[2307:48372] (
    firstThread
)-----<NSThread: 0x7fc3cac1b170>{number = 2, name = first}
2016-03-04 10:48:56.373 多线程demo[2307:48373] secondThread-----<NSThread: 0x7fc3cad05b80>{number = 3, name = (null)}
2016-03-04 10:48:56.373 多线程demo[2307:48374] (
    performSelectorInBackground
)-----<NSThread: 0x7fc3cad10770>{number = 4, name = (null)}

从运行结果可以看出,每种方式都开启了子线程。
(2)其他的隐式方式
这里写图片描述

2、GCD(重要),自动管理内存,C语言方法
两种队列:串行队列和并发队列
两个函数:同步函数dispatch_sync和异步函数dispatch_async(决定了要不要开启新的线程)

队列与函数结合使用的不同情况:
这里写图片描述
(1)全局并发队列添加到异步函数中

1、用dispatch_async异步函数往并发队列中添加任务—————》同时开启了3个子线程
- (void)asyncGlobalQueue
{
    // 获取一个全局的默认优先级的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.添加任务到队列中 执行
    dispatch_async(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
    });
    // 总结: 同时开启了3个线程
}

执行结果:
2016-03-04 11:24:58.042 多线程demo[2413:66032] ----下载图片1-----<NSThread: 0x7fe798e38510>{number = 2, name = (null)}
2016-03-04 11:24:58.042 多线程demo[2413:66033] ----下载图片3-----<NSThread: 0x7fe798e03720>{number = 4, name = (null)}
2016-03-04 11:24:58.042 多线程demo[2413:66031] ----下载图片2-----<NSThread: 0x7fe798f0b4b0>{number = 3, name = (null)}

(2)串行队列添加到异步函数中,开启了一条子线程

2、用dispatch_async异步函数 往串行队列中添加任务————————》只开了一个线程执行任务
- (void)asyncSerialQueue
{
    // 1.创建串行队列
    dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL);

    // 2.添加任务到队列中 执行
    dispatch_async(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
    });
   // 总结: 只开1个线程执行任务
}

执行结果:
2016-03-04 11:26:32.063 多线程demo[2426:67047] ----下载图片1-----<NSThread: 0x7f8dab521ff0>{number = 2, name = (null)}
2016-03-04 11:26:32.064 多线程demo[2426:67047] ----下载图片2-----<NSThread: 0x7f8dab521ff0>{number = 2, name = (null)}
2016-03-04 11:26:32.065 多线程demo[2426:67047] ----下载图片3-----<NSThread: 0x7f8dab521ff0>{number = 2, name = (null)}

(3)用dispatch_sync同步函数往并发队列中添加任务,不会开启新的线程,并发队列失去了并发的功能

3、用dispatch_sync同步函数往并发队列中添加任务—————》不会开启新的线程,并发队列失去了并发的功能
- (void)syncGlobalQueue
{
    // 1.获得全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    // 2.添加任务到队列中 执行
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
    });

    // 总结: 不会开启新的线程, 并发队列失去了并发的功能
}

执行结果
2016-03-04 11:31:42.592 多线程demo[2456:69917] ----下载图片1-----<NSThread: 0x7fe00a402310>{number = 1, name = main}
2016-03-04 11:31:42.592 多线程demo[2456:69917] ----下载图片2-----<NSThread: 0x7fe00a402310>{number = 1, name = main}
2016-03-04 11:31:42.593 多线程demo[2456:69917] ----下载图片3-----<NSThread: 0x7fe00a402310>{number = 1, name = main}

(4)同步函数执行串行队列,不会开启子线程

4、 用dispatch_sync同步函数往串行列中添加任务—————》不会开启新的线程
- (void)syncSerialQueue
{
    // 1.创建串行队列(串行队列)
    dispatch_queue_t queue = dispatch_queue_create("com.itheima.queue", NULL);

    // 2.添加任务到队列中 执行
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
    });

    // 3.释放资源
//    dispatch_release(queue);   // MRC(非ARC)

    // 总结: 不会开启新的线程
}

执行结果
2016-03-04 11:30:40.115 多线程demo[2443:69121] ----下载图片1-----<NSThread: 0x7fc5125086d0>{number = 1, name = main}
2016-03-04 11:30:40.116 多线程demo[2443:69121] ----下载图片2-----<NSThread: 0x7fc5125086d0>{number = 1, name = main}
2016-03-04 11:30:40.116 多线程demo[2443:69121] ----下载图片3-----<NSThread: 0x7fc5125086d0>{number = 1, name = main}

(5)用dispatch_sync同步函数, 在主线程中往主队列中添加任务 : 任务无法往下执行,产生死锁(死循环)

5、 用dispatch_sync同步函数, 在主线程中往主队列中添加任务 : 任务无法往下执行———————>产生死锁(死循环)
- (void)syncMainQueue
{
    // 1.获得主队列
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.添加任务到队列中 执行
     dispatch_sync(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
//    dispatch_sync(queue, ^{
//        NSLog(@"----下载图片2-----%@", [NSThread currentThread]);
//    });
//    dispatch_sync(queue, ^{
//        NSLog(@"----下载图片3-----%@", [NSThread currentThread]);
//    });

}

(6)异步函数, 在主线程中往主队列中添加任务

6、 使用dispatch_async异步函数, 在主线程中往主队列中添加任务
特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务), 任务在主线程执行,不会开启新的线程
- (void)asyncMainQueue
{
    // 1.获得主队列(串行队列)
    dispatch_queue_t queue = dispatch_get_main_queue();

    // 2.添加任务到队列中 执行
    dispatch_async(queue, ^{
        NSLog(@"----下载图片1-----%@", [NSThread currentThread]);
    });
}
执行结果
2016-03-04 11:35:42.321 多线程demo[2485:72362] ----下载图片1-----<NSThread: 0x7f82fa407d90>{number = 1, name = main}

(7)异步函数在全局并发队列中执行group中的任务,同步函数不能执行group中的任务

//异步函数在全局并发队列中执行group中的任务
-(void)asyncGlobalQueueGroup
{
    //获取到全局并发队列
    dispatch_queue_t global_queue =  dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_group_t group = dispatch_group_create();

    dispatch_group_async(group, global_queue, ^{
        for (int i = 0; i < 100; i ++) {
            NSLog(@"----下载图片1-----%@", [NSThread currentThread]);

        }    });

    dispatch_group_async(group, global_queue, ^{
        for (int i = 0; i < 100; i ++) {
            NSLog(@"----下载图片2-----%@", [NSThread currentThread]);

        }
    });
    //结果:在异步线程中并发执行group中的任务
}

3、NSOperation
NSOperation是对GCD的封装,将GCD封装成oc对象方便使用,NSOperation是抽象类,不能直接创建NSOperation的对象和调用对象方法,它有两个子类NSBlockOperation和NSInvocationOperation,使用时要用这两个方法来创建opreation对象、调用方法。
使用NSBlockOperation和NSInvocationOperation将需要的任务进行封装,

-(void)operation
{

    //1、封装任务
    NSBlockOperation *blockOpreation = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i < 100; i ++) {
            NSLog(@"----下载图片1-----%@", [NSThread currentThread]);

        }    }];
    [blockOpreation addExecutionBlock:^{
        for (int i = 0; i < 100; i ++) {
            NSLog(@"----下载图片2-----%@", [NSThread currentThread]);

        }
    }];

    //封装任务
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(run:) object:@[@"invocationOperation"]];
    //在blockOpreation中添加需要执行的任务

    //设置blockOpreation中任务的优先级为最高
    blockOpreation.queuePriority = NSOperationQueuePriorityVeryHigh;
//    NSInvocation *invovation = [[NSInvocation alloc]ini]
//    NSInvocationOperation *invoOpt = [[NSInvocationOperation alloc]initWithInvocation:<#(nonnull NSInvocation *)#>]

    //2、创建队列
    NSOperationQueue *optQueue = [[NSOperationQueue alloc]init];
    //最大并发数
    optQueue.maxConcurrentOperationCount = 1;

    //添加依赖,当blockOpreation中的任务执行完毕在执行invocationOperation中的任务
    [invocationOperation addDependency:blockOpreation];

    //将任务添加到队列中自动执行
    [optQueue addOperations:@[blockOpreation,invocationOperation] waitUntilFinished:YES];

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值