今天看了看线程,发现自己对线程还不是很了解,于是练了练手算是学习学习,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功能无比强大,脑洞打开后,拥有无限可能.学的很肤浅,技术还很渣,仍需努力,继续革命.
第二篇渣文出炉.