1. 多线程的一些相关概念
1.1 进程和线程:操作系统学习笔记之进程与线程
1.2 同步和异步
同步任务:在执行任务的过程中,按照顺序依次执行。
异步任务:在执行任务的过程中,可以同时触发执行。
1.3 串行和并行
串行队列:队列中任务依次执行。
并行队列:队列中任务同时执行。
2. 4种多线程操作情况
分别用同步串行、同步并行、异步串行和异步并行来执行以下函数。
-(void)task:(int)index{
for (int i = 0; i<2; i++) {
[NSThread sleepForTimeInterval:2];
NSLog(@"任务%d————当前线程:%@", index, [NSThread currentThread]);
}
}
2.1 同步执行串行任务队列
-(void)syncSerial{
dispatch_queue_t serialQueue = dispatch_queue_create("LJ_SERIAL_QUEUE", DISPATCH_QUEUE_SERIAL);
NSLog(@"开始同步串行任务————————当前线程:%@", [NSThread currentThread]);
dispatch_sync(serialQueue, ^{
[self task:1];
});
dispatch_sync(serialQueue, ^{
[self task:2];
});
dispatch_sync(serialQueue, ^{
[self task:2];
});
NSLog(@"结束同步串行任务————————当前线程:%@", [NSThread currentThread]);
}
输出日记
开始同步串行任务————————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务1————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务1————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
结束同步串行任务————————当前线程:<NSThread: 0x600001ae2fc0>{number = 1, name = main}
在同步中执行串行任务队列,不会创建新的线程,而且等待前一个任务执行完成之后才会去执行下一个任务。
2.2 同步执行并行任务队列
-(void)syncConcurrent{
dispatch_queue_t concurrentQueue = dispatch_queue_create("LJ_CONCURRENT_QUEUE", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"开始同步并行任务————————当前线程:%@", [NSThread currentThread]);
dispatch_sync(concurrentQueue, ^{
[self task:1];
});
dispatch_sync(concurrentQueue, ^{
[self task:2];
});
dispatch_sync(concurrentQueue, ^{
[self task:3];
});
NSLog(@"结束同步并行任务————————当前线程:%@", [NSThread currentThread]);
}
开始同步并行任务————————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务1————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务1————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务3————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
任务3————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
结束同步并行任务————————当前线程:<NSThread: 0x6000016711c0>{number = 1, name = main}
和同步串行任务的输出结果一模一样。也就是在同步任务中,串行队列和并行队列的执行结果都是一样的:不会创建新的线程,任务依次执行完成才会去执行下一个任务。
2.3 异步执行串行任务队列
-(void)asyncSerial{
dispatch_queue_t serialQueue = dispatch_queue_create("LJ_SERIAL_QUEUE", DISPATCH_QUEUE_SERIAL);
NSLog(@"开始异步串行任务————————当前线程:%@", [NSThread currentThread]);
dispatch_async(serialQueue, ^{
[self task:1];
});
dispatch_async(serialQueue, ^{
[self task:2];
});
dispatch_async(serialQueue, ^{
[self task:2];
});
NSLog(@"结束异步串行任务————————当前线程:%@", [NSThread currentThread]);
}
开始异步串行任务————————当前线程:<NSThread: 0x600003859400>{number = 1, name = main}
结束异步串行任务————————当前线程:<NSThread: 0x600003859400>{number = 1, name = main}
任务1————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
任务1————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
任务2————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
任务2————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
任务2————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
任务2————当前线程:<NSThread: 0x60000380fec0>{number = 3, name = (null)}
在异步执行串行任务时,会新建一个线程出来专门执行这个队列的任务。这些任务也是依次执行完成之后才能执行下一个任务。
2.4 异步执行并行任务队列
-(void)asyncConcurrent{
dispatch_queue_t concurrentQueue = dispatch_queue_create("LJ_CONCURRENT_QUEUE", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"开始异步并行任务————————当前线程:%@", [NSThread currentThread]);
dispatch_async(concurrentQueue, ^{
[self task:1];
});
dispatch_async(concurrentQueue, ^{
[self task:2];
});
dispatch_async(concurrentQueue, ^{
[self task:3];
});
NSLog(@"结束异步并行任务————————当前线程:%@", [NSThread currentThread]);
}
开始异步并行任务————————当前线程:<NSThread: 0x600001182940>{number = 1, name = main}
结束异步并行任务————————当前线程:<NSThread: 0x600001182940>{number = 1, name = main}
任务2————当前线程:<NSThread: 0x6000011ec080>{number = 3, name = (null)}
任务1————当前线程:<NSThread: 0x6000011cfc80>{number = 4, name = (null)}
任务3————当前线程:<NSThread: 0x6000011e0780>{number = 5, name = (null)}
任务2————当前线程:<NSThread: 0x6000011ec080>{number = 3, name = (null)}
任务3————当前线程:<NSThread: 0x6000011e0780>{number = 5, name = (null)}
任务1————当前线程:<NSThread: 0x6000011cfc80>{number = 4, name = (null)}
在异步执行并行任务时,不同的任务会创建不同的线程来执行,而且每个任务的执行都是并发的。
在执行异步任务时,不管并行还是串行任务,都会创建新的线程。而串行是只为整个任务队列创建一个线程,而并行则会为队列里面的每个任务都新建一个线程。
2.5 总结
在同步执行中,不管是串行队列还是并行队列,其行为都是一样的:都不会创建新的线程,任务都是依次完成在执行下一个。
在异步执行中,会为整个串行任务队列创建一个线程;并依次执行完任务、在并行任务队列中,会为每个任务都创建一个新的线程,并随机开始执行。
在iOS中,同步和异步的区别在于:是否基于原来的线程执行任务队列。同步是基于,而异步是新建一个线程。串行和并行的区别也在于:是否为每个人任务都新建一个线程来执行。串行是不会的,而并行是会为队列中的每个任务都新建一个线程。基于此,iOS开发中,并发编程的基础还是基于多线程本身的。
3. 主队列和主线程
每个APP都有且仅有一个主线程和一个主队列,它们随着APP的启动而创建,关闭而销毁。主队列是一个串行队列,它只能在主线程中执行。
获取主队列的方法:dispatch_get_main_queue
判读当前线程是否是主线程:NSThread.isMainThread
。isMainThread是一个类属性。
因为主队列只能在主线程中执行,所以就算使用异步执行主队列中的任务,也不会创建新的线程。如以下示例:
if (NSThread.isMainThread) {
NSLog(@"当前线程为主线程:%@", [NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"主队列异步任务:%@", [NSThread currentThread]);
});
}
当前线程为主线程:<NSThread: 0x600001361400>{number = 1, name = main}
主队列异步任务:<NSThread: 0x600001361400>{number = 1, name = main}
一般来说与APP界面更新有关和ViewController生命周期相关的都是在主线程中执行的。
不能在主线程中同步执行主队列中的任务,会引发线程死锁效应。
if (NSThread.isMainThread) {
NSLog(@"当前线程为主线程:%@", [NSThread currentThread]);
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"主队列异步任务:%@", [NSThread currentThread]);
});
}
当前线程为主线程:<NSThread: 0x60000002ac00>{number = 1, name = main}
(lldb)
以上,程序运行崩溃。
4. 全局并发队列
除了主队列之外,苹果官方还为我们提供了全局并发队列,它们是所有APP共用的队列。一般情况下,使用系统提供的全局并发队列就够了,不用再去创建新的并发队列。
dispatch_get_global_queue(long identifier, unsigned long flags);
identifier
参数为队列的优先级,flags
参数为标识,默认传0,如果传入其它值,可能会引发错误。
并发队列的优先级
// 最后优先级
#define DISPATCH_QUEUE_PRIORITY_HIGH 2
// 默认等级
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0
// 低等级
#define DISPATCH_QUEUE_PRIORITY_LOW (-2)
// 后台等级
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
网友评论