标签:
1、多线程的由来
2、耗时操作的模拟试验
3、进程和线程
4、多线程的概念及原理
5、多线程的优缺点和一个Tip
6、主线程
7、技术方案
二、Pthread
---
1、函数
2、参数和返回值
3、使用
三、NSThread
---
1、创建一个新的线程
2、线程的状态
3、线程的属性
四、互斥锁
---
1、访问共享资源引入问题!
2、互斥锁介绍
3、互斥锁原理
4、互斥锁和自旋锁
五、GCD
---
1、GCD介绍
2、GCD的两个核心
3、函数
4、串行队列和并发队列
5、主队列
6、全局队列
7、GCD总结
六、NSOperation
---
1、NSOperation简介
2、核心概念
3、操作步骤
4、NSInvocationOperation
5、NSBlockOperation
七、案例
---
***
一个进程(进程)在执行一个线程(线程中有很多函数或方法(后面简称Function))的时候,其中有一个Function执行的时候需要消耗一些时间,但是这个线程又必须同时执行这个Function之后的Function,问题来了,一个线程中的任何一个Function都必须等待其执行完成后才能执行后面的Function,如果要同时执行两个或者多个Function,那么,就必须多开一个或者多个线程,这就是多线程的产生。我想多线程最开始的诞生就是由这而来吧!
代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
}
NSLog(@"end");
}
return 0;
}
控制台
2016-02-16 13:51:54.140 Test[1670:603696] bengin
2016-02-16 13:51:54.160 Test[1670:603696] end
Program ended with exit code: 0
结论一:循环一亿次耗时0.02秒,计算机的运行速度是非常快的
代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
int n = 1;
}
NSLog(@"end");
}
return 0;
}
控制台
2016-02-16 13:57:37.589 Test[1734:631377] bengin
2016-02-16 13:57:37.612 Test[1734:631377] end
Program ended with exit code: 0
结论二:对栈区操作一亿次,耗时0.023秒
代码:
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSString *str = @"hellow";
}
NSLog(@"end");
}
return 0;
}
控制台
2016-02-16 14:03:59.003 Test[1763:659287] bengin
2016-02-16 14:03:59.113 Test[1763:659287] end
Program ended with exit code: 0
结论三:对常量区操作一亿次,耗时0.11秒
代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSString *str = [NSString stringWithFormat:@"%d",i];
}
NSLog(@"end");
}
return 0;
}
控制台
2016-02-16 14:09:03.673 Test[1786:673719] bengin
2016-02-16 14:09:10.705 Test[1786:673719] end
Program ended with exit code: 0
结论四:对堆区操作一亿次耗时7秒多一些,较慢!
代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
NSLog(@"bengin");
for (int i = 0; i < 10000000; i++) {
NSLog(@"%d",i);
}
NSLog(@"end");
}
return 0;
}
控制台输出!正在跑中,一亿次!!!先看截图
CPU
再看内存
好吧,还在跑,现在已经达到10分钟了,怕心疼本本炸掉!stop。。。
结论五:I/O操作非常慢,一亿次10分钟也没能跑完!
最终结论:通过以上结论一、二、三、四、五得出一个结论,各个区的执行效率:栈区>常量区>堆区>I/O操作。同时也说明了一个问题,执行不同的方法会产什么耗时操作。这是,为了解决耗时操作问题,多线程闪亮诞生!
先说说进程和线程吧!
系统中正在运行的应用程序。
每个进程都运行在其专用且受保护的内存空间,不同的进程之间相互独立,互不干扰。
线程是进程的执行任务的基本单元,一个进程的所有任务都是在线程中执行的。(每一个进程至少要有一条线程)。
线程在执行任务的时候是按顺序执行的。如果要让一条线程执行多个任务,那么只能一个一个地并且按顺序执行这些任务。也就是说,在同一时间,一条线程只能执行一个任务。
我们可以通过Mac中的活动监视器查看进程和线程,下图!
1个进程可以开启多条线程,多条线程可以同时执行不同的任务。
前提是在单核CPU的情况下,同一时间,CPU只能处理一条线程,也就是说只有一条线程在执行任务。多线程同时执行,那是不可能的!但是是CPU快速地在多条线程之间进行调度和切换执行任务。如果CPU调度线程的速度足够快,就会造成多条线程同时执行任务的”假象”,这种假象,就被美誉为:多线程!
可以适当提高程序的执行效率
也可以适当提高资源的利用率(CPU、内存利用率)
开启一条线程需要占用一定的内存空间(默认情况下,每一条线程都占用512KB),如果开启大量的线程,会占用大量的内存空间,从而降低程序的性能。
线程越多,CPU在调度和切换线程上的开销就会越大。
线程数越多,程序的设计会越复杂。
开启新的线程就会消耗资源,但是却可以提高用户体验。在保证良好的用户体验的前提下,可以适当地开线程,一般开3-6条。
开启一条新的线程,默认情况下,一条线程都是占用512KB,但是官方的文档里面给出的说明却不是,为了得出真相,下面做个小小的测试!
代码
int main(int argc, const char * argv[]) {
@autoreleasepool {
/** 操作主线程 /
NSLog(@"主线程默认 %tu", [NSThread currentThread].stackSize / 1024);
// 设置主线程的stackSize
[NSThread currentThread].stackSize = 1024 1024;
NSLog(@"主线程修改 %tu", [NSThread currentThread].stackSize / 1024);
/** 操作子线程 */
NSThread *thread = [[NSThread alloc] init];
NSLog(@"thread默认 %tu", thread.stackSize / 1024);
// 设置子线程的stackSize
thread.stackSize = 8 * 1024;
NSLog(@"thread修改 %tu", thread.stackSize / 1024);
[thread start];
}
return 0;
}
控制台
2016-02-17 08:36:02.652 Test[609:110129] 主线程默认 512
2016-02-17 08:36:02.654 Test[609:110129] 主线程修改 1024
2016-02-17 08:36:02.654 Test[609:110129] thread默认 512
2016-02-17 08:36:02.654 Test[609:110129] thread修改 8
结论七:证明了,不管什么线程,默认都是512,最小为8.可能是官方文档没有及时更新吧!
一个应用程序在启动运行后,系统会自动开启1条线程,这条称为”主线程”。
主线程上不能执行耗时操作,这样会造成界面卡顿,给用户一种不好的体验。
***
pthread_create(pthread_t *restrict, const pthread_attr_t *restrict, void *(*)(void *), void *restrict)
void *restrict 要执行的函数的参数
返回值 int类型 0是成功 非0 是失败
代码
#import <Foundation/Foundation.h>
#import <pthread/pthread.h>
void *demo(void *param) {
NSString *name = (__bridge NSString *)(param);
NSLog(@"hello %@ %@",name,[NSThread currentThread]);
return NULL;
}
int main(int argc, const char * argv[]) {
@autoreleasepool {
//创建子线程
pthread_t pthread; //线程编号
NSString *test = @"test";
int result = pthread_create(&pthread, NULL, demo, (__bridge void *)(test));
NSLog(@"Began %@",[NSThread currentThread]);
if (result == 0) {
NSLog(@"成功");
}else {
NSLog(@"失败");
}
}
return 0;
}
控制台
2016-02-16 22:00:57.401 Test[888:42585] Began <NSThread: x100502d70>{number = 1, name = main}
2016-02-16 22:00:57.403 Test[888:42615] hello test <NSThread: x100102a30>{number = 2, name = (null)}
2016-02-16 22:00:57.403 Test[888:42585] 成功
运行 Running
- (void)start;
阻塞(暂停) Blocked
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
死亡 Dead
+ (void)exit;
线程有两个重要的属性:名称和优先级
设置线程名用于记录线程,在出现异常时可以DeBug
优先级或者服务质量高的,可以优先调用,只是说会优先调用,但是不是百分之百的优先调用,这里存在一个概率问题,内核里的算法调度线程的时候,只是把优先级作为一个考虑因素,还有很多个因数会决定哪个线程优先调用。这点得注意注意!!!
下面是测试代码
控制台
2016-02-16 22:43:28.182 05-线程状态[1241:78688] 0--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-线程状态[1241:78689] 0--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.182 05-线程状态[1241:78688] 1--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-线程状态[1241:78688] 2--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.182 05-线程状态[1241:78689] 1--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 3--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-线程状态[1241:78689] 2--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 4--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 5--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-线程状态[1241:78689] 3--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 6--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 7--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.183 05-线程状态[1241:78689] 4--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.183 05-线程状态[1241:78688] 8--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 9--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 10--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78689] 5--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 11--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78689] 6--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 12--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 13--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78689] 7--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 14--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78688] 15--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-线程状态[1241:78688] 16--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.184 05-线程状态[1241:78689] 8--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.185 05-线程状态[1241:78688] 17--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-线程状态[1241:78688] 18--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-线程状态[1241:78689] 9--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.185 05-线程状态[1241:78688] 19--<NSThread: x7fead2017f30>{number = 2, name = test1}
2016-02-16 22:43:28.185 05-线程状态[1241:78689] 10--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-线程状态[1241:78689] 11--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-线程状态[1241:78689] 12--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-线程状态[1241:78689] 13--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.186 05-线程状态[1241:78689] 14--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-线程状态[1241:78689] 15--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-线程状态[1241:78689] 16--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-线程状态[1241:78689] 17--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-线程状态[1241:78689] 18--<NSThread: x7fead050a250>{number = 3, name = test2}
2016-02-16 22:43:28.187 05-线程状态[1241:78689] 19--<NSThread: x7fead050a250>{number = 3, name = test2}
结论六:优先级高,不一定先执行,只能说明先执行的概率要大一些!!!
结论六
得出服务质量和优先级不能决定线程执行的先后顺序,那么问题来了,一个线程对共享资源做了修改,而另外一个线程拿到的是未被修改之前资源,这是这个线程也对该资源做了修改,现在请问,两个线程都对该资源做了不同的修改,那么这个修改应该算谁的?!?!这就是问题所在!!!
这个文档里盗的图!
解决方案很简单,就是用一把锁锁住共享资源,等待线程1对其操作完毕后再打开,让线程2来执行,这就是传说中的互斥锁
!!!@synchronized(锁对象) { 需要锁定的代码 }
自旋锁就是atomic!
如果发现其它线程正在执行锁定代码,线程会进入休眠(阻塞状态),等其它线程时间片到了打开锁后,线程就会被唤醒(执行)。
如果发现有其它线程正在执行锁定代码,线程会以死循环的方式,一直等待锁定的代码执行完成。
***
队列的类型
void dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
void dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
// 1. 获取全局队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
// 2. 创建任务
dispatch_block_t task = ^ {
NSLog(@"hello %@", [NSThread currentThread]);
};
// 3. 将任务添加到队列,并且指定执行任务的函数
dispatch_async(queue, task);
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"hello %@", [NSThread currentThread]);
});
先进先出,按照顺序执行,并且一次只能调用一个任务
无论队列中所指定的执行任务的函数是同步还是异步,都必须等待前一个任务执行完毕才可以调用后面的人
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("test", NULL);
代码:
// 1、创建串行队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 2、将任务添加到队列,并且指定同步执行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@--%d",[NSThread currentThread],i);
});
}
打印结果:
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--0
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--1
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--2
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--3
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--4
2016-02-25 16:31:07.849 test[1924:376468] {number = 1, name = main}--5
2016-02-25 16:31:07.850 test[1924:376468] {number = 1, name = main}--6
2016-02-25 16:31:07.850 test[1924:376468] {number = 1, name = main}--7
2016-02-25 16:31:07.850 test[1924:376468] {number = 1, name = main}--8
2016-02-25 16:31:07.850 test[1924:376468] {number = 1, name = main}--9
结论:串行队列,同步执行,不开新线程,按顺序执行
代码:
// 1、创建串行队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_SERIAL);
// 2、将任务添加到队列,并且指定同步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@--%d",[NSThread currentThread],i);
});
}
打印结果:
2016-02-25 17:08:32.167 test[1959:391722] {number = 2, name = (null)}--0
2016-02-25 17:08:32.168 test[1959:391722] {number = 2, name = (null)}--1
2016-02-25 17:08:32.168 test[1959:391722] {number = 2, name = (null)}--2
2016-02-25 17:08:32.168 test[1959:391722] {number = 2, name = (null)}--3
2016-02-25 17:08:32.168 test[1959:391722] {number = 2, name = (null)}--4
2016-02-25 17:08:32.168 test[1959:391722] {number = 2, name = (null)}--5
2016-02-25 17:08:32.169 test[1959:391722] {number = 2, name = (null)}--6
2016-02-25 17:08:32.169 test[1959:391722] {number = 2, name = (null)}--7
2016-02-25 17:08:32.169 test[1959:391722] {number = 2, name = (null)}--8
2016-02-25 17:08:32.169 test[1959:391722] {number = 2, name = (null)}--9
结论:串行队列,异步执行,开启一条新的线程,按顺序执行
dispatch_queue_t q = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
代码:
// 1. 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
// 2. 将任务添加到队列, 并且指定同步执行
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
输出:
2016-02-25 17:18:38.039 test[1979:399667] {number = 1, name = main} 0
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 1
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 2
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 3
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 4
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 5
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 6
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 7
2016-02-25 17:18:38.040 test[1979:399667] {number = 1, name = main} 8
2016-02-25 17:18:38.041 test[1979:399667] {number = 1, name = main} 9
结论:并发队列,同步执行,不开线程,顺序执行
代码:
// 1. 创建并发队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT);
// 2. 将任务添加到队列, 并且指定同步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
输出:
2016-02-25 17:22:59.357 test[1992:403694] {number = 7, name = (null)} 6
2016-02-25 17:22:59.356 test[1992:403684] {number = 3, name = (null)} 1
2016-02-25 17:22:59.356 test[1992:403689] {number = 5, name = (null)} 3
2016-02-25 17:22:59.356 test[1992:403683] {number = 2, name = (null)} 0
2016-02-25 17:22:59.356 test[1992:403692] {number = 6, name = (null)} 4
2016-02-25 17:22:59.356 test[1992:403693] {number = 8, name = (null)} 5
2016-02-25 17:22:59.356 test[1992:403695] {number = 9, name = (null)} 7
2016-02-25 17:22:59.357 test[1992:403688] {number = 4, name = (null)} 2
2016-02-25 17:22:59.357 test[1992:403694] {number = 7, name = (null)} 9
2016-02-25 17:22:59.357 test[1992:403696] {number = 10, name = (null)} 8
结论:开启足够多的线程,不按照顺序执行
CPU在调度的时候以最高效的方式调度和执行任务,所以会开启多条线程,因为并发,执行顺序不一定
先进先出的,只有当主线程的代码执行完毕后,主队列才会调度任务到主线程执行
代码
// 1. 获取主队列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 将任务添加到主队列, 并且指定异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
// 先执行完这句代码, 才会执行主队列中的任务
NSLog(@"hello %@", [NSThread currentThread]);
打印
2016-02-25 21:10:43.293 test[773:786816] hello {number = 1, name = main}
2016-02-25 21:10:43.295 test[773:786816] {number = 1, name = main} 0
2016-02-25 21:10:43.295 test[773:786816] {number = 1, name = main} 1
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 2
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 3
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 4
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 5
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 6
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 7
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 8
2016-02-25 21:10:43.296 test[773:786816] {number = 1, name = main} 9
打印结果得出的一些结论
代码
NSLog(@"begin");
// 1. 获取主队列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 将任务添加到主队列, 并且指定同步执行
// 死锁
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
NSLog(@"end");
打印
2016-02-25 21:19:25.986 test[791:790967] begin
打印结果可以看出,不是想要的结果,这时候发生了死锁
在主线程执行,主队列同步执行任务,会发生死锁,主线程和主队列同步任务相互等待,造成死锁
代码
NSLog(@"begin");
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"--- %@", [NSThread currentThread]);
// 1. 获取主队列
dispatch_queue_t q = dispatch_get_main_queue();
// 2. 将任务添加到主队列, 并且指定同步执行
// 死锁
for (int i = 0; i < 10; i++) {
dispatch_sync(q, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
});
NSLog(@"end");
打印
2016-02-25 21:23:23.205 test[803:794826] begin
2016-02-25 21:23:23.206 test[803:794826] end
2016-02-25 21:23:23.206 test[803:794866] --- {number = 2, name = (null)}
2016-02-25 21:23:23.209 test[803:794826] {number = 1, name = main} 0
2016-02-25 21:23:23.209 test[803:794826] {number = 1, name = main} 1
2016-02-25 21:23:23.209 test[803:794826] {number = 1, name = main} 2
2016-02-25 21:23:23.209 test[803:794826] {number = 1, name = main} 3
2016-02-25 21:23:23.209 test[803:794826] {number = 1, name = main} 4
2016-02-25 21:23:23.210 test[803:794826] {number = 1, name = main} 5
2016-02-25 21:23:23.210 test[803:794826] {number = 1, name = main} 6
2016-02-25 21:23:23.210 test[803:794826] {number = 1, name = main} 7
2016-02-25 21:23:23.210 test[803:794826] {number = 1, name = main} 8
2016-02-25 21:23:23.210 test[803:794826] {number = 1, name = main} 9
全局队列是系统提供的,无需自己创建,可以直接通过dispatch_get_global_queue(long identifier, unsigned long flags);函数来获取。
代码
// 1. 获取全局队列
dispatch_queue_t q = dispatch_get_global_queue(0, 0);
// 2. 将任务添加到全局队列, 异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(q, ^{
NSLog(@"%d %@", i, [NSThread currentThread]);
});
}
打印输出
2016-02-25 21:29:06.978 test[816:799523] 1 {number = 3, name = (null)}
2016-02-25 21:29:06.978 test[816:799530] 4 {number = 6, name = (null)}
2016-02-25 21:29:06.978 test[816:799522] 0 {number = 2, name = (null)}
2016-02-25 21:29:06.978 test[816:799529] 3 {number = 5, name = (null)}
2016-02-25 21:29:06.978 test[816:799532] 6 {number = 7, name = (null)}
2016-02-25 21:29:06.978 test[816:799533] 7 {number = 8, name = (null)}
2016-02-25 21:29:06.978 test[816:799531] 5 {number = 9, name = (null)}
2016-02-25 21:29:06.978 test[816:799526] 2 {number = 4, name = (null)}
2016-02-25 21:29:06.979 test[816:799534] 8 {number = 10, name = (null)}
2016-02-25 21:29:06.979 test[816:799523] 9 {number = 3, name = (null)}
* 全局队列没有名称,无论ARC还是MRC都不需要考虑内存释放,日常开发,建议使用全局队列
* 并发队列有名称,如果在MRC开发中,需要使用dispatch_release来释放相应的对象,dispatch_barrier 必须使用自定义的并发队列,开发第三方框架,建议使用并发队列
dispatch_get_global_queue(long identifier, unsigned long flags);
这个函数中有两个参数:
第一个参数: identifier
iOS7.0,表示的是优先级:
DISPATCH_QUEUE_PRIORITY_HIGH = 2; 高优先级
DISPATCH_QUEUE_PRIORITY_DEFAULT = 0; 默认优先级
DISPATCH_QUEUE_PRIORITY_LOW = -2; 低优先级
DISPATCH_QUEUE_PRIORITY_BACKGROUND = INT16_MIN; 后台优先级
iOS8.0开始,推荐使用服务质量(QOS):
QOS_CLASS_USER_INTERACTIVE = 0x21; 用户交互
QOS_CLASS_USER_INITIATED = 0x19; 用户期望
QOS_CLASS_DEFAULT = 0x15; 默认
QOS_CLASS_UTILITY = 0x11; 实用工具
QOS_CLASS_BACKGROUND = 0x09; 后台
QOS_CLASS_UNSPECIFIED = 0x00; 未指定
通过对比可知: 第一个参数传入0,可以同时适配iOS7及iOS7以后的版本。
服务质量和优先级是一一对应的:
DISPATCH_QUEUE_PRIORITY_HIGH: QOS_CLASS_USER_INITIATED
DISPATCH_QUEUE_PRIORITY_DEFAULT: QOS_CLASS_DEFAULT
DISPATCH_QUEUE_PRIORITY_LOW: QOS_CLASS_UTILITY
DISPATCH_QUEUE_PRIORITY_BACKGROUND: QOS_CLASS_BACKGROUND
第二个参数: flags
为未来保留使用的,始终传入0。
Reserved for future use.
对主队列而言,不管是同步执行还是异步执行,都不会开线程。
代码
- (void)viewDidLoad {
[super viewDidLoad];
//创建操作,然后调用操作的start方法
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
NSLog(@"%d",op.isFinished);
[op start];
NSLog(@"%d",op.isFinished);
}
- (void)demo {
NSLog(@"hello %@",[NSThread currentThread]);
}
打印输出
2016-02-25 22:12:30.054 test[892:834660] 0
2016-02-25 22:12:30.054 test[892:834660] hello {number = 1, name = main}
2016-02-25 22:12:30.054 test[892:834660] 1
结论:[op start]在主线程中调用的,所以执行的线程也会是在主线程执行! 重复调用start也只会执行一次,因为NSOperation会有一个属性去记住,是否已经完成了该操作!
代码
- (void)viewDidLoad {
[super viewDidLoad];
// 创建操作,将操作添加到NSOperationQueue中,然后就会异步的自动执行
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo) object:nil];
//队列
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
//把操作添加到队列
[queue addOperation:op];
}
- (void)demo {
NSLog(@"hello %@",[NSThread currentThread]);
}
打印
2016-02-25 22:21:44.999 test[912:842412] hello {number = 2, name = (null)}
将操作添加到NSOperationQueue中,然后就会异步的自动执行
NSBlockOperation 中使用block的方式让所有代码逻辑在一起,使用起来更加简便。
代码
//创建操作
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
//更新op的状态,执行main方法,不会开新线程
[op start];
输出
2016-02-25 22:25:30.442 test[923:846208] hello {number = 1, name = main}
代码
// 创建队列,创建操作,将操作添加到队列中执行
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
[queue addOperation:op];
输出
2016-02-25 22:26:48.064 test[934:848038] hello {number = 2, name = (null)}
代码
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperationWithBlock:^{
NSLog(@"hello %@",[NSThread currentThread]);
}];
输出
2016-02-25 22:27:56.445 test[945:850128] hello <NSThread: x7f98dbc2cae0>{number = 2, name = (null)}
创建队列,添加block形式的操作
[self.queue addOperationWithBlock:^{
NSLog(@"异步下载图片");
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"回到主线程,更新UI");
}];
}];
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"下载图片---%@",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"回到主线程刷新图片的显示 -%@",[NSThread currentThread]);
});
});
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event { //新建状态 NSThread *test1 = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
test1.name = @"test1"; //线程的优先级 test1.threadPriority = 1.0; //就绪状态 [test1 start]; //新建状态 NSThread *test2= [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil]; test2.name = @"test2"; test2.threadPriority = 0; //就绪状态 [test2 start]; } //线程执行完成之后会自动销毁 - (void)demo { for (int i = 0; i < 20; i++) { NSLog(@"%d--%@",i,[NSThread currentThread]); } }
__bridge 桥接,把OC中的对象,传递给c语言的函数,使用__bridge
***
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(demo) object:nil];
[NSThread detachNewThreadSelector:@selector(demo) toTarget:self withObject:nil];
[self performSelectorInBackground:@selector(demo) withObject:nil];
标签:
原文地址:http://www.cnblogs.com/xiao-flag/p/5756956.html