1.进程与多线程
程序的执行依赖主线程
进程就是内存资源,线程争夺资源
访问网络,数据库的访问,可能会堵塞主线程的任务不要在主线程执行
2.创建多线程的六种方式(开辟线程)
// isMainThread
返回执行的代码是否在主线程中执行
BOOL bool1 = [[ NSThread currentThread ] isMainThread ];
NSLog ( @"bool1 is %d" , bool1);
// 第一种方式创建线程
NSThread *thread = [[ NSThread alloc ] initWithTarget : self selector : @selector (run) object : nil ];
// 手动开启线程
[thread start ];
// 第二种方式创建线程 类方法 不用手动开启线程
[ NSThread detachNewThreadSelector : @selector (run) toTarget : self withObject : nil ];
// 第三种方式创建 ( 重要 )
[ self performSelectorInBackground : @selector (run) withObject : nil ];
// 第四种方式创建 ( 重要 )
// NSOperationQueue 是一个操作队列或者是一个线程池
NSOperationQueue *queue = [[ NSOperationQueue alloc ] init ];
// // 可以获取到当前的操作队列或者是线程池 往主线程的当前操作队列中添加一个操作还是属于主线程的操作
// NSOperationQueue *queue = [NSOperationQueue currentQueue];
// // 往队列中添加一个操作
// [queue addOperationWithBlock:^{
// [self run];
// }];
// 第五种方式创建
// // 不要直接创建 NSOperation 操作对象 用它的子类
// NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// // 添加到操作队列中
// [queue addOperation:invocationOperation];
// 第六种方式 子类化一个 NSOperation ,将异步线程的方法写在子类化的 main 方法中
NewOperation *operation = [[ NewOperation alloc ] init ];
BOOL bool1 = [[ NSThread currentThread ] isMainThread ];
NSLog ( @"bool1 is %d" , bool1);
// 第一种方式创建线程
NSThread *thread = [[ NSThread alloc ] initWithTarget : self selector : @selector (run) object : nil ];
// 手动开启线程
[thread start ];
// 第二种方式创建线程 类方法 不用手动开启线程
[ NSThread detachNewThreadSelector : @selector (run) toTarget : self withObject : nil ];
// 第三种方式创建 ( 重要 )
[ self performSelectorInBackground : @selector (run) withObject : nil ];
// 第四种方式创建 ( 重要 )
// NSOperationQueue 是一个操作队列或者是一个线程池
NSOperationQueue *queue = [[ NSOperationQueue alloc ] init ];
// // 可以获取到当前的操作队列或者是线程池 往主线程的当前操作队列中添加一个操作还是属于主线程的操作
// NSOperationQueue *queue = [NSOperationQueue currentQueue];
// // 往队列中添加一个操作
// [queue addOperationWithBlock:^{
// [self run];
// }];
// 第五种方式创建
// // 不要直接创建 NSOperation 操作对象 用它的子类
// NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
// // 添加到操作队列中
// [queue addOperation:invocationOperation];
// 第六种方式 子类化一个 NSOperation ,将异步线程的方法写在子类化的 main 方法中
NewOperation *operation = [[ NewOperation alloc ] init ];
[queue addOperation:operation];
3.线程的常用方法
4.自动释放池,定时器在多线程的使用
//
在异步线程中,最好添加上自动释放池
@autoreleasepool {
/*
在异步线程中,不会一直 runloop
*/
// // 此方法只是创建定时器,但是并没有添加到 runloop 中
// NSTimer *timer1 = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//
// // 将定时器添加到 runloop 中
// [[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSDefaultRunLoopMode];
// 此方法默认将定时器添加到了 runloop 中了
// [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//
// [[NSRunLoop currentRunLoop] run];
/*
http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg
*/
// 在异步线程中加载图片
NSString *imgStr = @"http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg" ;
NSData *imgData = [ NSData dataWithContentsOfURL :[ NSURL URLWithString :imgStr]];
// 注意:所有有关 UI的操作必须放在主线程中执行
@autoreleasepool {
/*
在异步线程中,不会一直 runloop
*/
// // 此方法只是创建定时器,但是并没有添加到 runloop 中
// NSTimer *timer1 = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//
// // 将定时器添加到 runloop 中
// [[NSRunLoop currentRunLoop] addTimer:timer1 forMode:NSDefaultRunLoopMode];
// 此方法默认将定时器添加到了 runloop 中了
// [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction:) userInfo:nil repeats:YES];
//
// [[NSRunLoop currentRunLoop] run];
/*
http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg
*/
// 在异步线程中加载图片
NSString *imgStr = @"http://f.hiphotos.baidu.com/image/pic/item/cf1b9d16fdfaaf51dea4d4a88f5494eef01f7a65.jpg" ;
NSData *imgData = [ NSData dataWithContentsOfURL :[ NSURL URLWithString :imgStr]];
// 注意:所有有关 UI的操作必须放在主线程中执行
[selfperformSelectorOnMainThread:@selector(showImage:)withObject:imgData waitUntilDone:NO];//waitUntilDone在主线程中执行完要不要再到异步线程
5.GCD
线程在执行处理时,存在两种Queue
主线程队列自然是Serial Dispatch Queue
Global Dispatch Queue(系统默认创建的异步线程队列)是所有应用程序都能够使用的Concurrent Dispatch Queue
//
创建
Serial Dispatch Queue
dispatch_queue_t serialqueue = dispatch_queue_create ( "serial" , DISPATCH_QUEUE_SERIAL );
// 创建 Concurrent Dispatch Queue
dispatch_queue_t concurrentqueue = dispatch_queue_create ( "concurrent" , DISPATCH_QUEUE_CONCURRENT );
// 在 MRC 情况下 释放
// dispatch_release(serialqueue);
// dispatch_release(concurrentqueue);
// 获取系统主线程队列
dispatch_queue_t queue = dispatch_get_main_queue ();
// 获取系统默认创建的的异步线程队列
dispatch_queue_t globalQueue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ); // 优先级
// 同步添加
// 造成死锁 1
// 在主线程队列中添加一个任务,因为是同步,所以需要等到这个任务前的所有的任务执行完了,才会继续往下走
// 但是新添加的任务要想执行,由于放在队列的末尾,必须等到添加的操作执行完了才能继续
NSLog ( @"begin" );
// // 只需改成 dispatch_async ,异步添加,可以用异步线程来执行,不用一直等待就可以解开死锁了
dispatch_queue_t serialqueue = dispatch_queue_create ( "serial" , DISPATCH_QUEUE_SERIAL );
// 创建 Concurrent Dispatch Queue
dispatch_queue_t concurrentqueue = dispatch_queue_create ( "concurrent" , DISPATCH_QUEUE_CONCURRENT );
// 在 MRC 情况下 释放
// dispatch_release(serialqueue);
// dispatch_release(concurrentqueue);
// 获取系统主线程队列
dispatch_queue_t queue = dispatch_get_main_queue ();
// 获取系统默认创建的的异步线程队列
dispatch_queue_t globalQueue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 ); // 优先级
// 同步添加
// 造成死锁 1
// 在主线程队列中添加一个任务,因为是同步,所以需要等到这个任务前的所有的任务执行完了,才会继续往下走
// 但是新添加的任务要想执行,由于放在队列的末尾,必须等到添加的操作执行完了才能继续
NSLog ( @"begin" );
// // 只需改成 dispatch_async ,异步添加,可以用异步线程来执行,不用一直等待就可以解开死锁了
dispatch_sync(queue, ^{
NSLog
(
@"sync
”
); //它等着被添加上去才能执行
});//因为是往同一个线程上同步添加,所以只有等到block块中代码执行完才能往下走
dispatch_sync(queue1, block);假设该语句在queue0中执行,则会阻塞(等待)queue0直到queue1中的block执行结束。当queue0和queue1不同时,queue0与queue1为并行执行,此时queue0等待,queue1执行block,queue0与queue1互不影响,直到queue1的block执行结束,queue0阻塞也结束,即dispatch_sync语句返回。当queue0和queue1相同(且为串行队列Serial Dispatch Queue)时,即dispatch_sync与block在同一个队列中,此时queue0已经阻塞,不可能再执行block,更无法等待block执行结束,因此造成死锁。
官方文档指出:dispatch_sync的当前执行队列与提交block执行的目标队列相同时将造成死锁。
// 死锁 2
// 外层 在主线程中添加一个任务,因为是异步添加,所以不需要等待添加任务完成,因此能够输出 end
// 里层 用同步添加任务到主线程队列,因此又回到死锁 1 ,因此程序卡死,不能执行
NSLog ( @"begin" );
dispatch_async (queue, ^{
NSLog(@"async");
//死锁1
dispatch_sync
(queue, ^{
NSLog ( @"sync" );
});
});
NSLog ( @"sync" );
});
});
NSLog(@"end");
实现两个线程之间的交互
//
添加异步队列,将执行的任务添加到异步队列中
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSData
*data = [
NSData
dataWithContentsOfURL
:url];
UIImage *image = [ UIImage imageWithData :data];
// 回到主线程也要异步添加(永远不要同步添加到主线程中)
dispatch_async ( dispatch_get_main_queue (), ^{
self . image = image;
});
UIImage *image = [ UIImage imageWithData :data];
// 回到主线程也要异步添加(永远不要同步添加到主线程中)
dispatch_async ( dispatch_get_main_queue (), ^{
self . image = image;
});
});
①dispatch_suspend dispatch_resume
②dispatch_once
单例
+ (
id
)sharePerson
{
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
// 以下方法只会执行一次
ps = [[ Person alloc ] init ];
});
return ps ;
{
static dispatch_once_t onceToken;
dispatch_once (&onceToken, ^{
// 以下方法只会执行一次
ps = [[ Person alloc ] init ];
});
return ps ;
}
③
dispatch_after
//CGD
延迟调用
// 原理: dispatch_after 并不是指定时间后执行任务处理,而是指定时间后,将任务添加到队列中,所以会有少许的延迟
// 注意:不能取消已经提交到 dispatch_after Block 代码块中的代码
/*
void
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
dispatch_time_t when: 延迟的时间
dispatch_queue_t queue: 具体添加到某个队列中
dispatch_block_t block: 具体执行的任务
*/
// 代码执行到此处的时间
CFAbsoluteTime first = CFAbsoluteTimeGetCurrent ();
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC ));
dispatch_after (time, dispatch_get_main_queue (), ^{
// 延迟调用这里边的代码
NSLog ( @" 代码执行到这里共用了 %f" , CFAbsoluteTimeGetCurrent () - first);
});
// 原理: dispatch_after 并不是指定时间后执行任务处理,而是指定时间后,将任务添加到队列中,所以会有少许的延迟
// 注意:不能取消已经提交到 dispatch_after Block 代码块中的代码
/*
void
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
dispatch_time_t when: 延迟的时间
dispatch_queue_t queue: 具体添加到某个队列中
dispatch_block_t block: 具体执行的任务
*/
// 代码执行到此处的时间
CFAbsoluteTime first = CFAbsoluteTimeGetCurrent ();
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC ));
dispatch_after (time, dispatch_get_main_queue (), ^{
// 延迟调用这里边的代码
NSLog ( @" 代码执行到这里共用了 %f" , CFAbsoluteTimeGetCurrent () - first);
});
④
dispatch_group
//dispatch_group
的使用
dispatch_group_t group= dispatch_group_create ();
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
// 往异步线程中添加具有 group 属性的任务
dispatch_group_async (group, queue, ^{
// 睡眠 5s
sleep ( 2 );
NSLog ( @"block1" );
});
dispatch_group_async (group, queue, ^{
NSLog ( @"block2" );
});
dispatch_group_async (group, queue, ^{
NSLog ( @"block3" );
});
// 结果汇总 dispatch_group_notify 所有的任务结束汇总,不阻塞线程
// dispatch_group_notify(group, queue, ^{
// NSLog(@" 结束了汇总 ");
// });
// 结果汇总 dispatch_group_wait 等待直到所有的任务执行结束,中途不能取消,阻塞当前线程
// 对 block 的时间永久等待
// dispatch_time_t time = DISPATCH_TIME_FOREVER;// 持久的时间
// dispatch_group_wait(group, time);// 等待 group 全部结束
//
// 设定 group 等待的时间 也是阻塞的时间
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 1 * NSEC_PER_SEC ));
// 等待 group 中全部任务结束的时间,如果所等待的 group 时间小于 time ,则返回 0 ,等待的时间是 0
long result = dispatch_group_wait (group, time);
if (result == 0 ) {
NSLog ( @" 任务全部结束 " );
} else {
NSLog ( @" 任务还没有全部结束 " );
}
NSLog ( @"end" );
dispatch_group_t group= dispatch_group_create ();
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
// 往异步线程中添加具有 group 属性的任务
dispatch_group_async (group, queue, ^{
// 睡眠 5s
sleep ( 2 );
NSLog ( @"block1" );
});
dispatch_group_async (group, queue, ^{
NSLog ( @"block2" );
});
dispatch_group_async (group, queue, ^{
NSLog ( @"block3" );
});
// 结果汇总 dispatch_group_notify 所有的任务结束汇总,不阻塞线程
// dispatch_group_notify(group, queue, ^{
// NSLog(@" 结束了汇总 ");
// });
// 结果汇总 dispatch_group_wait 等待直到所有的任务执行结束,中途不能取消,阻塞当前线程
// 对 block 的时间永久等待
// dispatch_time_t time = DISPATCH_TIME_FOREVER;// 持久的时间
// dispatch_group_wait(group, time);// 等待 group 全部结束
//
// 设定 group 等待的时间 也是阻塞的时间
dispatch_time_t time = dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 1 * NSEC_PER_SEC ));
// 等待 group 中全部任务结束的时间,如果所等待的 group 时间小于 time ,则返回 0 ,等待的时间是 0
long result = dispatch_group_wait (group, time);
if (result == 0 ) {
NSLog ( @" 任务全部结束 " );
} else {
NSLog ( @" 任务还没有全部结束 " );
}
NSLog ( @"end" );
⑤
dispatch_apply
dispatch_apply按指定的次数,将指定的Block追加到指定的Dispatch Queue中,并等待全部处理执行结束。(一般用于数量较大的循环迭代)
NSArray *arrar = @[@0 , @1 , @2 , @3 , @4 , @5 , @6 , @7 , @8] ;
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
/*
size_t iterations遍历执行的次数
queue执行操作在的队列
block
执行的具体任务
使用 dispatch_apply 执行效率比一般的 for 循环执行效率要高
*/
dispatch_async (queue, ^{
// 执行的顺序是不确定的,不是按数组的顺序执行的
dispatch_apply (arrar. count , queue, ^( size_t index) {
NSLog ( @"%zu is %@" , index, arrar[index]);
});
// 执行更新(在主线程中)
dispatch_async ( dispatch_get_main_queue (), ^{
NSLog ( @"done" );
});
});
使用 dispatch_apply 执行效率比一般的 for 循环执行效率要高
*/
dispatch_async (queue, ^{
// 执行的顺序是不确定的,不是按数组的顺序执行的
dispatch_apply (arrar. count , queue, ^( size_t index) {
NSLog ( @"%zu is %@" , index, arrar[index]);
});
// 执行更新(在主线程中)
dispatch_async ( dispatch_get_main_queue (), ^{
NSLog ( @"done" );
});
});
⑥dispatch_barrier_async
用异步的方式添加,但为了异步写的时候,别的读取出错,需要对写的进行加锁,即在写的过程中,不会受到其他的影响,所以用
dispatch_barrier_async可以同步的添加写的任务。
⑦Dispatch Semaphore
// dispatch_semaphore
//
创建一个信号量
信号量为
1
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 1 );
NSMutableArray *mArr = [ NSMutableArray array ];
for ( int i = 0 ; i < 100000 ; i ++) {
// 异步增加到异步线程队列
dispatch_async (queue, ^{
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 1 );
NSMutableArray *mArr = [ NSMutableArray array ];
for ( int i = 0 ; i < 100000 ; i ++) {
// 异步增加到异步线程队列
dispatch_async (queue, ^{
//等待,等待条件:如果信号量>0,则不需要等待,信号量-1,否则需要等待,等到信号量>0
dispatch_semaphore_wait
(semaphore,
DISPATCH_TIME_FOREVER
);
// 如果不使用信号量的话,可能任务并发,同一个数重复添加,造成内存地址争夺而崩溃
[mArr addObject : @( i ) ];
// 发信号,使信号量加 1
dispatch_semaphore_signal (semaphore);
});
}
// 这句话在主线程上执行,这时异步线程可能还没有执行完循环
NSLog ( @"mArr.count %ld" , mArr. count );
// 延迟执行
dispatch_after ( dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC )), dispatch_get_main_queue (), ^{
NSLog ( @"mArr.count %ld" , mArr. count );
// 看是否有重复只需放在集合中
NSSet *set = [ NSSet setWithArray :mArr];
NSLog ( @"set.count, %ld" , set. count );
// 如果不使用信号量的话,可能任务并发,同一个数重复添加,造成内存地址争夺而崩溃
[mArr addObject : @( i ) ];
// 发信号,使信号量加 1
dispatch_semaphore_signal (semaphore);
});
}
// 这句话在主线程上执行,这时异步线程可能还没有执行完循环
NSLog ( @"mArr.count %ld" , mArr. count );
// 延迟执行
dispatch_after ( dispatch_time ( DISPATCH_TIME_NOW , ( int64_t )( 3 * NSEC_PER_SEC )), dispatch_get_main_queue (), ^{
NSLog ( @"mArr.count %ld" , mArr. count );
// 看是否有重复只需放在集合中
NSSet *set = [ NSSet setWithArray :mArr];
NSLog ( @"set.count, %ld" , set. count );
});
⑧GCD控制多线程并发
//CGD
控制多线程并发
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
// 创建一个 group
dispatch_group_t group = dispatch_group_create ();
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 3 );
for ( int i = 0 ; i < 10 ; i++) {
// 使用 group 的异步添加到异步线程
// 当信号量小于 0 的时候,等待 放在哪个线程中都不影响,都会记住信号量的多少,放在这里可以卡在添加到线程队列之前
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async (group, queue, ^{
// 当信号量小于 0 的时候,等待,添加到这可以卡在打印之前
dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER );
NSLog ( @"%d" , i);
sleep ( 1 );
if (i == 2 ) {
sleep ( 3 );
}
// 发出信号量,信号量加 1
dispatch_semaphore_signal (semaphore);
});
dispatch_queue_t queue = dispatch_get_global_queue ( DISPATCH_QUEUE_PRIORITY_DEFAULT , 0 );
// 创建一个 group
dispatch_group_t group = dispatch_group_create ();
dispatch_semaphore_t semaphore = dispatch_semaphore_create ( 3 );
for ( int i = 0 ; i < 10 ; i++) {
// 使用 group 的异步添加到异步线程
// 当信号量小于 0 的时候,等待 放在哪个线程中都不影响,都会记住信号量的多少,放在这里可以卡在添加到线程队列之前
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_group_async (group, queue, ^{
// 当信号量小于 0 的时候,等待,添加到这可以卡在打印之前
dispatch_semaphore_wait (semaphore, DISPATCH_TIME_FOREVER );
NSLog ( @"%d" , i);
sleep ( 1 );
if (i == 2 ) {
sleep ( 3 );
}
// 发出信号量,信号量加 1
dispatch_semaphore_signal (semaphore);
});
}
// 等 group 中的任务全部结束之前一直等待,卡主线程
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"group end");