您的位置:首页 > 移动开发 > IOS开发

iOS 多线程与GCD

2015-09-02 11:54 393 查看
1.进程与多线程



程序的执行依赖主线程
进程就是内存资源,线程争夺资源
访问网络,数据库的访问,可能会堵塞主线程的任务不要在主线程执行

2.创建多线程的六种方式(开辟线程)
// isMainThread返回执行的代码是否在主线程中执行

BOOL bool1 = [[NSThreadcurrentThread]isMainThread];

NSLog(@"bool1 is %d", bool1);

//第一种方式创建线程

NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(run)object:nil];

//手动开启线程

[thread
start];

//第二种方式创建线程类方法不用手动开启线程

[NSThreaddetachNewThreadSelector:@selector(run)toTarget:selfwithObject:nil];

// 第三种方式创建(重要)

[selfperformSelectorInBackground:@selector(run)withObject:nil];

// 第四种方式创建(重要)

// NSOperationQueue是一个操作队列或者是一个线程池

NSOperationQueue *queue = [[NSOperationQueuealloc]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 = [[NewOperationalloc]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 = [NSDatadataWithContentsOfURL:[NSURLURLWithString: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_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(@"end");

实现两个线程之间的交互
//添加异步队列,将执行的任务添加到异步队列中
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
^{

NSData *data = [NSDatadataWithContentsOfURL:url];

UIImage *image = [UIImageimageWithData: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 = [[Personalloc]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_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_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_tindex)
{

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 = [NSMutableArrayarray];

for (inti =
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 = [NSSetsetWithArray: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 (inti =
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");
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: