多线程的概念不再赘述,iOS开发中总的来讲可用的多线程方法一共有四种。
多线程的优点
能适当提高程序的执行效率
能适当提高资源利用率(CPU、内存利用率)
多线程的缺点
创建线程是有开销的,iOS下主要成本包括:内核数据结构(大约1KB)、栈空间(子线程512KB、主线程1MB,也可以使用-setStackSize:设置,但必须是4K的倍数,而且最小是16K),创建线程大约需要90毫秒的创建时间
如果开启大量的线程,会降低程序的性能
线程越多,CPU在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享
pthread
一套通用的多线程API
适用于Unix\Linux\Windows等系统
跨平台\可移植
使用难度大
NSThread
面向对象,偶尔使用,需要手动管理生命周期,其实也只是需要你手动去开启线程。
// 简单用法
//创建线程
NSThread*thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(run:)object:@"jack"];
thread.name=@"my-thread";
//启动线程
[threadstart];
[NSThreaddetachNewThreadSelector:@selector(run:)toTarget:selfwithObject:@"rose"];
// 消息传递
[selfperformSelectorInBackground:@selector(run:)withObject:@"jack"];
还有一些其他常用方法,具体不再赘述。
GCD
基于c语言,能够充分利用设备的多核,具体方法如下
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//GCD:主要关注两个内容
//同步执行,异步执行;
//队列:主对列,全局子队列,自定义队列;
//主队列:
dispatch_queue_tmainQueue =dispatch_get_main_queue();//获取主队列;
//获取全局子队列:
//优先级:
// DISPATCH_QUEUE_PRIORITY_DEFAULT默认优先级:
dispatch_queue_tglobalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
#if0
//在主对列发起同步任务,主线程等待等待任务执行,任务又在主线程里面等待主线程,造成互相等待,卡顿:
//在主队列发起同步任务:
dispatch_sync(mainQueue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
#endif
#if0
//在全局队列发起同步任务:
dispatch_sync(globalQueue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
#endif
#if0
//用于在子线程回到主线程执行: (常用做法) √
dispatch_async(mainQueue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
#endif
#if0
//异步任务,全局子队列: (用到) √
//会开启子线程执行任务:
//可以开启多条子线程:
dispatch_async(globalQueue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(globalQueue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
#endif
#if0
//参数二: 0表示串行队列:
dispatch_queue_t customQueue1 = dispatch_queue_create("custom",0);
//串行队列只创建一条子线程,所有任务在这条线程里串行执行:
dispatch_async(customQueue1, ^{
NSLog(@"%@", [NSThread currentThread]);
});
dispatch_async(customQueue1, ^{
NSLog(@"%@", [NSThread currentThread]);
});
#endif
//参数二: DISPATCH_QUEUE_CONCURRENT表示并发队列:
dispatch_queue_tcustomQueue2 =dispatch_queue_create("custom2",DISPATCH_QUEUE_CONCURRENT);
//并发队列,可以开启多条线程:
dispatch_async(customQueue2, ^{
NSLog(@"%@", [NSThreadcurrentThread]);
});
dispatch_async(customQueue2, ^{
NSLog(@"%@", [NSThreadcurrentThread]);
});
//一段时间执行对应的代码:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)),dispatch_get_main_queue(), ^{
UIAlertView*a = [[UIAlertViewalloc]initWithTitle:@"弹框"message:nildelegate:nilcancelButtonTitle:nilotherButtonTitles:@"确定",nil];
[ashow];
});
NSLog(@".....");
//只会执行一次:
// static dispatch_once_t onceToken;
// dispatch_once(&onceToken, ^{
// <#code to be executed once#>
// });
// [SingleExample shareSingle];
// [[SingleExample alloc] init];
// [[SingleExample alloc] init];
// [UIApplication sharedApplication];
// [NSNotificationCenter defaultCenter];
// [NSFileManager defaultManager];
NSLog(@"%p", [SingleExampleshareSingle]);
NSLog(@"%p", [SingleExampleshareSingle]);
NSLog(@"%p", [SingleExampleshareSingle]);
// NSLog(@"%p", [[SingleExample alloc] init]);
//分组执行任务:
//创建分组:
dispatch_group_tgroup =dispatch_group_create();
//异步执行第一组任务:
dispatch_group_async(group, globalQueue, ^{
NSLog(@"第一个任务%@", [NSThreadcurrentThread]);
});
dispatch_group_async(group, globalQueue, ^{
NSLog(@"第二个任务%@", [NSThreadcurrentThread]);
});
//等待其他任务执行完才执行:
dispatch_group_notify(group, globalQueue, ^{
NSLog(@"第三个任务%@", [NSThreadcurrentThread]);
});
[NSThreaddetachNewThreadSelector:@selector(doSomeThing:)toTarget:selfwithObject:nil];
}
- (void)doSomeThing:(id)obj
{
//下载网络数据:
//返回主线程刷新UI界面:
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"refreshUI%@", [NSThreadcurrentThread]);
});
}
单粒写法
staticSingleExample*single =nil;
@implementationSingleExample
+ (SingleExample*)shareSingle
{
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
single= [[SingleExamplealloc]init];
});
returnsingle;
}
NSOperation
基于GCD(底层是GCD)
比GCD多了一些更简单实用的功能
使用更加面向对象
代码如下
@interfaceViewController()
//线程队列,也称为线程池;
@property(nonatomic,strong)NSOperationQueue*queue;
@end
@implementationViewController
- (NSOperationQueue*)queue
{
if(_queue==nil) {
_queue= [[NSOperationQueuealloc]init];
}
return_queue;
}
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)doOp1:(id)obj
{
for(inti =0; i <5; i++) {
NSLog(@"op1");
[NSThreadsleepForTimeInterval:1.0];
}
}
- (IBAction)clickStart:(id)sender {
// NSOperation的子类
//通过方法创建任务:
//执行方法里面的代码:
NSInvocationOperation*op1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doOp1:)object:nil];
//通过block方法创建任务:
//执行block里面的代码:
NSBlockOperation*op2 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"op2");
}];
NSBlockOperation*op3 = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"op3");
}];
//最大的线程个数:
// self.queue.maxConcurrentOperationCount = 1; //串行执行;
//依赖顺序关系:
[op2addDependency:op1];// op2等待op1执行完才执行;
[op3addDependency:op1];// op3等待op1执行完才执行;
// op2,op3与op1串行;
// op2和op3并发执行
//把任务放到线程队列里:
[self.queueaddOperation:op3];
[self.queueaddOperation:op2];
[self.queueaddOperation:op1];
// [op1 cancel];
}
- (IBAction)clickStop:(id)sender {
//取消正在等待的任务:
[self.queuecancelAllOperations];
}
@end
下面说下线程安全
在某些情况下,如果多个子线程同时访问同一个方法或者变量,就会导致信息错误,比如数据覆盖混乱等,那么在这种情况下就需要设置线程锁。
线程锁就是锁住线程,他会等上一个子线程进入并执行完操作之后,下一个子线程才会进来执行操作,如果是成员变量的话,一般使用原子性,即natomic,如果是方法函数,则有两种方法
一是NSLOCK
创建NSLOCK
NSLock*lock = [[NSLockalloc]init];
//加锁
[locklock];
// 中间是访问的方法
// method
//解锁
[lockunlock];
第二种就是关键字synchronized
示例方法
while(1) {
@synchronized(self) {
// method
}
}