iOS 多线程与GCD

1.进程与多线程
程序的执行依赖主线程
进程就是内存资源,线程争夺资源
访问网络,数据库的访问,可能会堵塞主线程的任务不要在主线程执行

2.创建多线程的六种方式(开辟线程)
  // isMainThread 返回执行的代码是否在主线程中执行
   
BOOL bool1 = [[ NSThread currentThread ] isMainThread ];
   
NSLog ( @"bool1 is %d" , bool1);
   
   
// 第一种方式创建线程
   
NSThread *thread = [[ NSThread alloc ] initWithTarget : self selector : @selector (run) object : nil ];
   
// 手动开启线程
    [thread
start ];
   
   
// 第二种方式创建线程 类方法 不用手动开启线程
    [
NSThread detachNewThreadSelector : @selector (run) toTarget : self withObject : nil ];
   
   
//    第三种方式创建 ( 重要 )
    [
self performSelectorInBackground : @selector (run) withObject : nil ];
   
//    第四种方式创建 ( 重要 )
//    NSOperationQueue 是一个操作队列或者是一个线程池
   
NSOperationQueue *queue = [[ NSOperationQueue alloc ] init ];
   
//    // 可以获取到当前的操作队列或者是线程池 往主线程的当前操作队列中添加一个操作还是属于主线程的操作
//    NSOperationQueue *queue = [NSOperationQueue currentQueue];
   
//    // 往队列中添加一个操作
//    [queue addOperationWithBlock:^{
//        [self run];
//    }];

   
// 第五种方式创建
//    // 不要直接创建 NSOperation 操作对象 用它的子类
//    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
//    // 添加到操作队列中
//    [queue addOperation:invocationOperation];
   
   
// 第六种方式 子类化一个 NSOperation ,将异步线程的方法写在子类化的 main 方法中
   
NewOperation *operation = [[ NewOperation alloc ] init ];
    [queue addOperation:operation];
3.线程的常用方法

4.自动释放池,定时器在多线程的使用
// 在异步线程中,最好添加上自动释放池
   
@autoreleasepool {
       
       
/*
        
在异步线程中,不会一直 runloop
        
         */

       
       
//        // 此方法只是创建定时器,但是并没有添加到 runloop
//        NSTimer *timer1 = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//       
//        // 将定时器添加到 runloop
//        [[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSDefaultRunLoopMode];
       
       
       
// 此方法默认将定时器添加到了 runloop 中了
//        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//       
//        [[NSRunLoop currentRunLoop] run];
       
       
       
/*
         http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg
         */

       
       
// 在异步线程中加载图片
       
NSString *imgStr = @"http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg" ;
       
NSData *imgData = [ NSData dataWithContentsOfURL :[ NSURL URLWithString :imgStr]];
       
// 注意:所有有关 UI的操作必须放在主线程中执行
        [selfperformSelectorOnMainThread:@selector(showImage:)withObject:imgData waitUntilDone:NO];//waitUntilDone在主线程中执行完要不要再到异步线程

5.GCD
线程在执行处理时,存在两种Queue
主线程队列自然是Serial Dispatch Queue
Global Dispatch Queue(系统默认创建的异步线程队列)是所有应用程序都能够使用的Concurrent Dispatch Queue


   // 创建 Serial Dispatch Queue
        
dispatch_queue_t serialqueue = dispatch_queue_create ( "serial" , DISPATCH_QUEUE_SERIAL );

       
// 创建 Concurrent Dispatch Queue
       
dispatch_queue_t concurrentqueue = dispatch_queue_create ( "concurrent" , DISPATCH_QUEUE_CONCURRENT );
       
       
// MRC 情况下 释放
//        dispatch_release(serialqueue);
//        dispatch_release(concurrentqueue);
       
       
// 获取系统主线程队列
       
dispatch_queue_t queue = dispatch_get_main_queue ();
       
       
// 获取系统默认创建的的异步线程队列
       
dispatch_queue_t globalQueue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ); // 优先级
       
       
// 同步添加
       
// 造成死锁 1
       
// 在主线程队列中添加一个任务,因为是同步,所以需要等到这个任务前的所有的任务执行完了,才会继续往下走
       
// 但是新添加的任务要想执行,由于放在队列的末尾,必须等到添加的操作执行完了才能继续
       
NSLog ( @"begin" );
//        // 只需改成 dispatch_async ,异步添加,可以用异步线程来执行,不用一直等待就可以解开死锁了
        dispatch_sync(queue, ^{
            NSLog ( @"sync ); //它等着被添加上去才能执行
        });//因为是往同一个线程上同步添加,所以只有等到block块中代码执行完才能往下走

dispatch_sync(queue1, block);假设该语句在queue0中执行,则会阻塞(等待)queue0直到queue1中的block执行结束。当queue0和queue1不同时,queue0与queue1为并行执行,此时queue0等待,queue1执行block,queue0与queue1互不影响,直到queue1的block执行结束,queue0阻塞也结束,即dispatch_sync语句返回。当queue0和queue1相同(且为串行队列Serial Dispatch Queue)时,即dispatch_sync与block在同一个队列中,此时queue0已经阻塞,不可能再执行block,更无法等待block执行结束,因此造成死锁。
官方文档指出:dispatch_sync的当前执行队列与提交block执行的目标队列相同时将造成死锁。
       

       
       
// 死锁 2
       
// 外层 在主线程中添加一个任务,因为是异步添加,所以不需要等待添加任务完成,因此能够输出 end
       
// 里层 用同步添加任务到主线程队列,因此又回到死锁 1 ,因此程序卡死,不能执行
       
       
NSLog ( @"begin" );
       
       
dispatch_async (queue, ^{
           
            NSLog(@"async");
            //死锁1
            dispatch_sync (queue, ^{
               
NSLog ( @"sync" );
            });

        });
        NSLog(@"end");

实现两个线程之间的交互
// 添加异步队列,将执行的任务添加到异步队列中
 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
        NSData *data = [ NSData dataWithContentsOfURL :url];
       
UIImage *image = [ UIImage imageWithData :data];
       
// 回到主线程也要异步添加(永远不要同步添加到主线程中)
       
dispatch_async ( dispatch_get_main_queue (), ^{
           
self . image = image;
        });
    });

①dispatch_suspend dispatch_resume

②dispatch_once
单例
+ ( id )sharePerson
{
   
   
static dispatch_once_t onceToken;
   
dispatch_once (&onceToken, ^{
       
// 以下方法只会执行一次
       
ps = [[ Person alloc ] init ];
    });
   
return ps ;
}

dispatch_after
//CGD 延迟调用
   
   
// 原理: dispatch_after 并不是指定时间后执行任务处理,而是指定时间后,将任务添加到队列中,所以会有少许的延迟
   
   
// 注意:不能取消已经提交到 dispatch_after Block 代码块中的代码
   
/*
     void
     dispatch_after(dispatch_time_t when,
     dispatch_queue_t queue,
     dispatch_block_t block);
    
     dispatch_time_t when:
延迟的时间
     dispatch_queue_t queue:
具体添加到某个队列中
     dispatch_block_t block:
具体执行的任务

     */

   
   
// 代码执行到此处的时间
   
CFAbsoluteTime first = CFAbsoluteTimeGetCurrent ();
   
   
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC ));
   
   
dispatch_after (time, dispatch_get_main_queue (), ^{
       
// 延迟调用这里边的代码
       
NSLog ( @" 代码执行到这里共用了 %f" , CFAbsoluteTimeGetCurrent () - first);
    });

dispatch_group
//dispatch_group 的使用
       
dispatch_group_t group= dispatch_group_create ();
       
       
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
       
       
// 往异步线程中添加具有 group 属性的任务
       
dispatch_group_async (group, queue, ^{
           
// 睡眠 5s
           
sleep ( 2 );
           
NSLog ( @"block1" );
        });
       
       
dispatch_group_async (group, queue, ^{
           
NSLog ( @"block2" );
        });
       
       
dispatch_group_async (group, queue, ^{
           
NSLog ( @"block3" );
        });
       
       
// 结果汇总 dispatch_group_notify 所有的任务结束汇总,不阻塞线程
//        dispatch_group_notify(group, queue, ^{
//            NSLog(@" 结束了汇总 ");
//        });
       
       
       
// 结果汇总 dispatch_group_wait 等待直到所有的任务执行结束,中途不能取消,阻塞当前线程
       
// block 的时间永久等待
//        dispatch_time_t time = DISPATCH_TIME_FOREVER;// 持久的时间
//        dispatch_group_wait(group, time);// 等待 group 全部结束
//
       
// 设定 group 等待的时间 也是阻塞的时间
       
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 1 * NSEC_PER_SEC ));
       
// 等待 group 中全部任务结束的时间,如果所等待的 group 时间小于 time ,则返回 0 ,等待的时间是 0
       
long result = dispatch_group_wait (group, time);
       
       
if (result == 0 ) {
           
NSLog ( @" 任务全部结束 " );
        }
else {
           
NSLog ( @" 任务还没有全部结束 " );
        }
       
       
       
NSLog ( @"end" );
dispatch_apply
dispatch_apply按指定的次数,将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。(一般用于数量较大的循环迭代)

       
       
NSArray *arrar = @[@0 , @1 , @2 , @3 , @4 , @5 , @6 , @7 , @8] ;
       
       
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
       
       
/*
        size_t iterations遍历执行的次数
        queue执行操作在的队列
        block 执行的具体任务
        
        
使用 dispatch_apply 执行效率比一般的 for 循环执行效率要高
         */

       
dispatch_async (queue, ^{
           
           
// 执行的顺序是不确定的,不是按数组的顺序执行的
           
dispatch_apply (arrar. count , queue, ^( size_t index) {
               
NSLog ( @"%zu is %@" , index, arrar[index]);
            });
           
           
// 执行更新(在主线程中)
           
dispatch_async ( dispatch_get_main_queue (), ^{
               
NSLog ( @"done" );
            });
           
        });


⑥dispatch_barrier_async
用异步的方式添加,但为了异步写的时候,别的读取出错,需要对写的进行加锁,即在写的过程中,不会受到其他的影响,所以用 dispatch_barrier_async可以同步的添加写的任务。

⑦Dispatch Semaphore
// dispatch_semaphore
        // 创建一个信号量 信号量为 1
           
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 1 );
       
NSMutableArray *mArr = [ NSMutableArray array ];
       
       
for ( int i = 0 ; i < 100000 ; i ++) {
           
// 异步增加到异步线程队列
           
dispatch_async (queue, ^{
       //等待,等待条件:如果信号量>0,则不需要等待,信号量-1,否则需要等待,等到信号量>0
                dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER );
               
// 如果不使用信号量的话,可能任务并发,同一个数重复添加,造成内存地址争夺而崩溃
                [mArr
addObject : @( i ) ];
               
               
// 发信号,使信号量加 1
               
dispatch_semaphore_signal (semaphore);
               
            });
        }
       
       
// 这句话在主线程上执行,这时异步线程可能还没有执行完循环
       
NSLog ( @"mArr.count %ld" , mArr. count );
       
       
// 延迟执行
       
dispatch_after ( dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC )), dispatch_get_main_queue (), ^{
           
NSLog ( @"mArr.count %ld" , mArr. count );
           
           
// 看是否有重复只需放在集合中
           
NSSet *set = [ NSSet setWithArray :mArr];
           
NSLog ( @"set.count, %ld" , set. count );
        });
⑧GCD控制多线程并发
  //CGD 控制多线程并发
       
       
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
       
       
// 创建一个 group
       
dispatch_group_t group = dispatch_group_create ();
       
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 3 );
       
       
for ( int i = 0 ; i < 10 ; i++) {
           
           
// 使用 group 的异步添加到异步线程
           
           
// 当信号量小于 0 的时候,等待 放在哪个线程中都不影响,都会记住信号量的多少,放在这里可以卡在添加到线程队列之前
//            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
           
           
dispatch_group_async (group, queue, ^{
               
// 当信号量小于 0 的时候,等待,添加到这可以卡在打印之前
               
dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER );
               
               
NSLog ( @"%d" , i);
               
               
sleep ( 1 );
               
if (i == 2 ) {
                   
sleep ( 3 );
                }
               
// 发出信号量,信号量加 1
               
dispatch_semaphore_signal (semaphore);
            });

        }
       
       
// group 中的任务全部结束之前一直等待,卡主线程
        dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
        NSLog(@"group end");








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值