线程之GCD

今天看了看线程,发现自己对线程还不是很了解,于是练了练手算是学习学习,iOS中线程一共分为四种:Pthread,NSThread,GCD 和 NSOperation.
Pthread基本不用,很多系统中都支持,iOS中也支持.但是基本不用.

NSThread我还很菜,也许是我知道的不多,我所知道的确实不难,具体有啥,在Xcode中点进去看看里面的属性和方法一目了然,这里多说一句在swift中,Thread取消了Perform.......的自启动方法.

GCD:根据目前本菜鸟所学,需要注意的关键点为队列(queue),任务,组(group).队列分串行队列(DISPATCH_QUEUE_SERIAL)和并行队列(DISPATCH_QUEUE_CONCURRENT) 任务分为同步(sync)和异步(async)

1.异步执行,并发队列

- (void)GCDasyncConcurrentThread {
    dispatch_queue_t queue1 = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after1");
    });
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after2");
    });
    
    dispatch_async(queue1, ^{
        NSLog(@"%@",[NSThread currentThread]);
//        NSLog(@"%@",[NSThread currentThread]);

        dispatch_async(queue1, ^{
            NSLog(@"zzz%@",[NSThread currentThread]);
        });
        NSLog(@"after3");
    });
    
    NSLog(@"after");
} 
2017-01-24 13:15:46.738 GCD学习[3445:112733] {number = 3, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112735] {number = 5, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112732] {number = 4, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112697] after
2017-01-24 13:15:46.738 GCD学习[3445:112733] after1
2017-01-24 13:15:46.738 GCD学习[3445:112761] zzz{number = 6, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112735] after3
2017-01-24 13:15:46.738 GCD学习[3445:112732] after2
2017-01-24 13:15:46.738 GCD学习[3445:112762] zzz{number = 7, name = (null)}
2017-01-24 13:15:46.738 GCD学习[3445:112763] zzz{number = 8, name = (null)}

并发异步执行,会开启线程,并且队列中线程的执行顺序不确定,多写几个耗时不同的线程会发现,当开启新线程之前会检查当前队列中是否存在闲置线程 ,如果有闲置线程,便用闲置线程执行要执行的操作,如果没有闲置线程便新开一条线程。

2.异步执行 串行队列

//GCD 异步执行 串行队列 产生新线程   同一队列只会产生一个线程
- (void)GCDasyncSrialThread {
    NSLog(@"before");
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"now:1");
        [NSThread currentThread].name = @"thread1";
        NSLog(@"%@",[NSThread currentThread]);
    });

    dispatch_async(queue, ^{
        NSLog(@"now:2");
        NSLog(@"%@",[NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"now:4");
            NSLog(@"%@",[NSThread currentThread]);
        });
    });
    
    dispatch_async(queue, ^{
        NSLog(@"now:3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
    NSLog(@"%@",[NSThread currentThread]);
}
2017-01-24 13:26:12.327 GCD学习[3537:116874] before
2017-01-24 13:26:12.328 GCD学习[3537:116874] after
2017-01-24 13:26:12.328 GCD学习[3537:116923] now:1
2017-01-24 13:26:12.328 GCD学习[3537:116874] {number = 1, name = main}
2017-01-24 13:26:12.328 GCD学习[3537:116923] {number = 3, name = thread1}
2017-01-24 13:26:12.328 GCD学习[3537:116923] now:2
2017-01-24 13:26:12.328 GCD学习[3537:116923] {number = 3, name = thread1}
2017-01-24 13:26:12.329 GCD学习[3537:116923] now:3
2017-01-24 13:26:12.329 GCD学习[3537:116923] {number = 3, name = thread1}
2017-01-24 13:26:12.329 GCD学习[3537:116923] now:4
2017-01-24 13:26:12.329 GCD学习[3537:116923] {number = 3, name = thread1}

一个串行队列中执行异步操作只会产生一个子线程,并且所有执行的异步操作先进入队列的先操作,后进入队列的后操作。此处now4实在子线程中开辟一条新线程,如果将now4的异步(async)改为同步(sync)程序会崩溃,产生线程阻塞,同步执行不会产生新线程,后面后提到.

3.同步执行 串行队列

//GCD 同步执行 串行队列 不产生新线程   线程阻塞
- (void)GCDsyncSrialThread {
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);
    NSLog(@"before");
    dispatch_sync(queue, ^{
        
        NSLog(@"now1");
        [NSThread currentThread].name = @"thread1";
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        
//        dispatch_sync(queue, ^{
//            NSLog(@"now4");
//            NSLog(@"%@",[NSThread currentThread]);
//        });
        
        NSLog(@"now2");
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
}
2017-01-24 13:48:36.036 GCD学习[3729:125159] before
2017-01-24 13:48:36.036 GCD学习[3729:125159] now1
2017-01-24 13:48:36.036 GCD学习[3729:125159] {number = 1, name = thread1}
2017-01-24 13:48:36.036 GCD学习[3729:125159] now2
2017-01-24 13:48:36.036 GCD学习[3729:125159] {number = 1, name = thread1}
2017-01-24 13:48:36.037 GCD学习[3729:125159] now3
2017-01-24 13:48:36.037 GCD学习[3729:125159] {number = 1, name = thread1}
2017-01-24 13:48:36.037 GCD学习[3729:125159] after

串行队列中同步执行任务,不会产生新的子线程,并且执行顺序为先进入队列的任务先执行,后进入队列的后执行,前一个任务未完成不会进入后一个任务,所以上面代码中被注掉的部分打开运行时会卡在此处,产生线程阻塞.原因是因为在队列中,now4加入队列需要等待now2线程执行完才能进行,而now2中后面的语句执行要在now4执行后执行,这是互相等待都不执行就产生了线程阻塞.将now4的同步(sync)改为异步(async)就可以解决线程阻塞问题.但在实际开发中问题的解决并非这么简单,要考虑实际情况以及任务执行顺序.上面提到的线程阻塞也是相互等待产生的问题

4.同步执行 并行队列

//GCD 同步执行 并行队列 不产生新线程
- (void)GCDsyncConcurrentThread {
    dispatch_queue_t queue = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    NSLog(@"before");
    dispatch_sync(queue, ^{
        [NSThread currentThread].name = @"thread1";
        NSLog(@"now:1");
        NSLog(@"%@",[NSThread currentThread]);
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now:2");
        NSLog(@"%@",[NSThread currentThread]);
        
        dispatch_sync(queue, ^{
            NSLog(@"now:4");
            NSLog(@"%@",[NSThread currentThread]);
        });
    });
    
    dispatch_sync(queue, ^{
        NSLog(@"now:3");
        NSLog(@"%@",[NSThread currentThread]);
    });
    NSLog(@"after");
    NSLog(@"%@",[NSThread currentThread]);
}
2017-01-24 14:03:28.900 GCD学习[3904:132214] before
2017-01-24 14:03:28.900 GCD学习[3904:132214] now:1
2017-01-24 14:03:28.900 GCD学习[3904:132214] {number = 1, name = thread1}
2017-01-24 14:03:28.900 GCD学习[3904:132214] now:2
2017-01-24 14:03:28.900 GCD学习[3904:132214] {number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] now:4
2017-01-24 14:03:28.901 GCD学习[3904:132214] {number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] now:3
2017-01-24 14:03:28.901 GCD学习[3904:132214] {number = 1, name = thread1}
2017-01-24 14:03:28.901 GCD学习[3904:132214] after
2017-01-24 14:03:28.901 GCD学习[3904:132214] {number = 1, name = thread1}

并行队列 同步执行不会产生新线程, 所有任务按代码顺序执行,在并同步任务中添加同步任务,可以在上层任务未完成时执行内部任务,可以想象为遇到什么事情 就解决什么事,不分进入队列时间,一切按执行过程走.

5.GCD 队列组

//GCD 队列组
- (void)GCDgroup{
    dispatch_group_t group = dispatch_group_create();
    
    dispatch_queue_t queue1 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t queue2 = dispatch_queue_create("", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_queue_t queue3 = dispatch_queue_create("", DISPATCH_QUEUE_SERIAL);

    dispatch_group_async(group, queue1, ^{
        NSLog(@"1");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"2");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"3");
    });
    dispatch_group_async(group, queue1, ^{
        NSLog(@"4");
    });
    dispatch_group_async(group, queue1, ^{
        NSLog(@"5");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"6");
    });
    dispatch_group_async(group, queue2, ^{
        NSLog(@"7");
    });
    dispatch_group_async(group, queue3, ^{
        NSLog(@"8");
    });
    dispatch_group_async(group, queue3, ^{
        NSLog(@"9");
    });
    dispatch_group_notify(group, queue1, ^{
        NSLog(@"wan");
    });
}
2017-01-24 15:01:17.948 GCD学习[4371:151987] 2
2017-01-24 15:01:17.948 GCD学习[4371:151971] 1
2017-01-24 15:01:17.948 GCD学习[4371:151972] 8
2017-01-24 15:01:17.948 GCD学习[4371:151974] 4
2017-01-24 15:01:17.948 GCD学习[4371:151990] 3
2017-01-24 15:01:17.948 GCD学习[4371:151991] 5
2017-01-24 15:01:17.948 GCD学习[4371:151992] 6
2017-01-24 15:01:17.949 GCD学习[4371:151993] 7
2017-01-24 15:01:17.949 GCD学习[4371:151987] 9
2017-01-24 15:01:17.949 GCD学习[4371:151993] wan

队列组中装的是队列,组中所有队列执行结束会执行dispatch_group_notify(<#dispatch_group_t _Nonnull group#>, <#dispatch_queue_t _Nonnull queue#>, <#^(void)block#>)

队列组中还有一些其他的API,如
dispatch_group_enter(dispatch_group_t group);在组内加入执行代码块 与leave要同时出现 不然会crash.
dispatch_group_leave(dispatch_group_t group);
dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);检查组内任务多久之后是否完成是否完成,如果完成,返回值为0,否则不为0如:
dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5*NSEC_PER_SEC));设定等待5秒,观察五秒后是否组内任务全部完成,如果未完成继续执行组内任务 返回非0数继续执行,如果在5秒内完成则返回0,继续后续执行.所以此API无论返回什么,并不影响程序运行.
dispatch_apply API是sync与group的关联,将block中的执行加入到queue中关联一个组. iterations重复次数,queue队列,和带残block,index为每次任务标号,无序执行.可无序遍历容器类.

dispatch_apply(10, queue3, ^(size_t index) {
        
    });```
还有dispatch_after 延迟操作,延迟多久在哪个队列中执行什么操作.
dispatch_once 只执行一次的操作,可用于单例.在类方法中

static Class class = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
class = [[Class alloc]init];
});
return class;

还有另外一种单例写法,和两种的严格与不严格形式,啥时候有遇到相关内容再带一下吧.都很简单.
GCD功能无比强大,脑洞打开后,拥有无限可能.学的很肤浅,技术还很渣,仍需努力,继续革命.
第二篇渣文出炉.

你可能感兴趣的:(线程之GCD)