知识点一:
NSOperation是个抽象类。只能使用它的子类来封装任务。有三种方式来封装任务。
- 使用子类NSInvocationOperation
- 使用子类NSBlockOperation
- 定义继承自NSOperation的子类,通过实现内部相应的方法来封装任务。
NSOperation(不使用NSOperationQueue的情况下)需要使用start() 才能开启操作, 并且默认情况下(只有一个操作,如果有两个或多个操作呢?)在当前线程中同步执行操作;
注意:当前线程的判定条件是是start() 调起的地方,不是operation声明 或者执行任务操作的线程中,也就是说start()在哪一线程中调起,改操作就会在那一个线程中执行,无论 具体的任务操作是在哪一个线程中定义的;举个例子:
//main线程中声明NSBlockOperation
op = [[NSBlockOperation alloc] init];
//在分线程中添加具体的操作 [NSThread detachNewThreadWithBlock:^{ [op addExecutionBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"具体操作指令:%@:::%d",[NSThread currentThread],i); } }]; }];
- (void)gotostart{ NSLog(@"哪一个?:%@===%@",[NSThread currentThread],[NSThread currentThread].name); [op start]; } - (void)buttonClick{ //点击button 创建一个新的线程 在新线程中start(); NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(gotostart) object:nil]; [thread setName:@"我是新的线程"]; [thread start]; }
2015-09-18 23:21:01.980 af[15270:6402146] 定义NSBlockOperation的线程:<NSThread: 0x600000066b00>{number = 1, name = main} 2015-09-18 23:21:01.981 af[15270:6402196] 创建操作的线程:<NSThread: 0x6000000698c0>{number = 3, name = (null)} 2015-09-18 23:21:11.892 af[15270:6402575] 调用start的线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}===我是新的线程 2015-09-18 23:21:12.893 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::1 2015-09-18 23:21:13.898 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::2 2015-09-18 23:21:14.899 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::3 2015-09-18 23:21:15.903 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::4 2015-09-18 23:21:16.906 af[15270:6402575] 具体操作指令线程:<NSThread: 0x60000006ebc0>{number = 4, name = 我是新的线程}:::5
如果只有一个操作(操作1)的时候会在start函数调起的线程中同步执行操作,如果有两个或多个操作呢?
答:会开启新的线程,在新的线程中执行第二个操作(操作2) 此时操作1的线程和操作2的线程是并发的;操作2线程内部是同步的
op = [[NSBlockOperation alloc] init]; NSLog(@"定义NSBlockOperation的线程:%@",[NSThread currentThread]); [NSThread detachNewThreadWithBlock:^{ NSLog(@"创建操作的线程:%@",[NSThread currentThread]); [op addExecutionBlock:^{ int i = 0; while (i<10) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"第一个操作:%@:::%d",[NSThread currentThread],i); } }]; [op addExecutionBlock:^{ [NSThread detachNewThreadWithBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"具体操作指令线程A:%@:::%d",[NSThread currentThread],i); } }]; [NSThread detachNewThreadWithBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"具体操作指令线程B:%@:::%d",[NSThread currentThread],i); } }]; }]; }];
2015-09-18 23:44:13.163 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::7 2015-09-18 23:44:13.612 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::7 2015-09-18 23:44:14.168 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::8 2015-09-18 23:44:14.675 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::8 2015-09-18 23:44:15.174 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::9 2015-09-18 23:44:15.741 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::9 2015-09-18 23:44:16.180 af[15337:6437620] 第一个操作:<NSThread: 0x600000078e80>{number = 4, name = 我是新的线程}:::10 2015-09-18 23:44:16.814 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::10 2015-09-18 23:44:17.884 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::11 2015-09-18 23:44:18.900 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::12 2015-09-18 23:44:19.970 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::13 2015-09-18 23:44:21.040 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::14 2015-09-18 23:44:22.081 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::15 2015-09-18 23:44:23.155 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::16 2015-09-18 23:44:24.226 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::17 2015-09-18 23:44:25.299 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::18 2015-09-18 23:44:26.374 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::19 2015-09-18 23:44:27.387 af[15337:6437292] 具体操作指令线程A:<NSThread: 0x600000078cc0>{number = 5, name = (null)}:::20 2015-09-18 23:44:28.389 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::1 2015-09-18 23:44:29.389 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::2 2015-09-18 23:44:30.395 af[15337:6438077] 具体操作指令线程B:<NSThread: 0x608000067f40>{number = 6, name = (null)}:::3
那么 默认情况下 系统线程池会开启多少个线程 ?
答:默认66个线程 其中有2个是系统的,64个是我们可以使用的;
最大并发数不要乱写(5以内),不要开太多,一般以2~3为宜,因为虽然任务是在子线程进行处理的,但是cpu处理这些过多的子线程可能会影响UI,让UI变卡。
线程的花销:(来自官方文档,没有研究这个花销是否包含上下文切换时的场景记忆等花销);
512 KB (secondary threads)
8 MB (OS X main thread)
1 MB (iOS main thread)
知识点二:
NSOperationQueue
[NSOperationQueue mainQueue];
queue = [[NSOperationQueue alloc] init];
operation加入到队列中,如果当前operation个数(线程(线程个数并不一定等于operation个数))小于可以开启的最大peration(线程)个数,那么它会在很短的时间内就开始了这一个operation;
添加的operation 都是在分线程中执行的;
queue.maxConcurrentOperationCount = 2;
// 这个参数表示的是operation的最大个数,并不是开启线程的最大个数 //一个operation可以有多个操作,第一个操作在当前线程,其他操作开启了新的线程;每一个线程都是同步执行的;
op = [[NSBlockOperation alloc] init]; [op addExecutionBlock:^{ int i = 0; while (i<10) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"op_1------:%@:::%d",[NSThread currentThread],i); } }]; [op addExecutionBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"op_2=-----%@:::%d",[NSThread currentThread],i); } }]; // blocks cannot be added after the operation has started executing or finished' op1 = [[NSBlockOperation alloc] init]; [op1 addExecutionBlock:^{ [NSThread sleepForTimeInterval:2]; int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"op1=-----%@:::%d",[NSThread currentThread],i); } }]; op2 = [[NSBlockOperation alloc] init]; [op2 addExecutionBlock:^{ int i = 0; while (i<20) { i++; [NSThread sleepForTimeInterval:1]; NSLog(@"op2=-----%@:::%d",[NSThread currentThread],i); } }];
添加依赖等设置;
//op1 依赖于op2 也就是说op2执行完之后 op1才开始 (网络请求也是这个顺序,执行顺序,并不是数据返回顺序) [op1 addDependency:op2]; [queue addOperation:op];
这一个是阻塞当前线程; 直到op这个操作执行完成;可用于线程执行顺序的同步
[op waitUntilFinished];
[queue addOperation:op1]; [queue addOperation:op2];
[op1 cancel];
[queue cancelAllOperations];
操作的是在队列中等待的操作;