在单线程中一个线程只能做一件事情,一件事情处理不完另一件事就不能开始,这样势必影响用户体验。
在没有顺序要求的情况下使用多线程既能解决线程阻塞又能充分利用多核处理器运行能力。
在 iOS 中其实目前有 4 套多线程方案,他们分别是:
Pthreads
NSThread
NSOperation & NSOperationQueue
GCD
Pthreads简单地说,这是一套在很多操作系统上都通用的多线程API,所以移植性很强(然并卵),当然在 iOS 中也是可以的。不过这是基于 c语言 的框架。想要自己实现一套多线程方案,从底层开始定制,那么可以去搜一下相关资料。
后三种方式是随着iOS的发展逐渐引入的,所以相比而言后者比前者更加简单易用,并且GCD也是目前苹果官方比较推荐的方式(它充分利用了多核处理器的运算性能)
接下来简单说下它们的创建:
1.Pthreads: (大多数情况下用不到)
- (void)touchesBegan:(NSSet )touches withEvent:(UIEvent )event {
pthread_t thread;
//创建一个线程并自动执行
pthread_create(&thread, NULL, start, NULL);
}
void start(void data) {
NSLog(@”%@”, [NSThread currentThread]);
return NULL;
}
2.NSThread
// 创建
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:nil];
// 启动
[thread start];
// 取消
[thread cancel];
// 创建并自动启动
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:nil];
更多方法大家可以去类的定义里去看。
GCD
// 后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
// something
});// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});// 延迟2秒执行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// code to be executed on the main queue after delay
});// 自定义dispatch_queue_t
dispatch_queue_t urls_queue = dispatch_queue_create(“blog.devtang.com”, NULL);
dispatch_async(urls_queue, ^{
// your code
});
dispatch_release(urls_queue);// 合并汇总结果
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
// 汇总结果
});
4.NSOperation & NSOperationQueue
NSOperation *operation = [[NSOperation alloc] init];
[operation start];
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在调用start方法的那个线程中直接执行。NSOperation对象的isConcurrent方法会告诉我们这个操作相对于调用start方法的线程,是同步还是异步执行。isConcurrent方法默认返回NO,表示操作与调用线程同步执行.
start方法用来启动一个Operation任务。同时,Operation提供一个main方法,你的所有任务都应该在main中进行处理。默认的start方法中会先做出一些异常判断然后直接调用main方法。如果需要自定义一个NSOperation必须重载main方法来执行你所想要执行的任务。
-(void)main {
@try {
// Do some work.
}
@catch(…) {
// Exception handle.
}
}
@end
如果你把NSOperation交给队列去维护,只需要实现main方法就行了,但是你如果想要手动去控制这个线程(启动。。。),需要自己调用start方法,但是这样是不安全的,因为若 没有获得充分资源,而此时你调用start方法,就会抛出异常。这是官方文档里面说的。
[operation cancel];
至于star和main的区别,到论坛里看到有这样说的:实现main方法, 线程串行执行; 实现start方法, 线程并发执行.
NSOperationQueue queue = [NSOperationQueue new];
NSInvocationOperation operation = [[NSInvocationOperation alloc];
initWithTarget:self
selector:@selector(doWork:)
object:someObject];
[queue addObject:operation];
还有关于
串行是排成一列,像糖葫芦。串行是一次只能执行一个任务,并行是排成一行一次能执行多个任务
并行是CPU的多核芯同时执行多个任务, 并发是单核CPU交替执行两个任务
这里再加几个名词解释:
进程:一个可执行的程序
任务:一块可执行的代码
线程:指的是一个独立的代码执行路径,线程是代码执行路径的最小分支
同步 和 串行的区别 ?
异步 和 并行的区别 ?
关于这个问题我暂时没有想到答案,只是觉得它们在某些地方类似,但是完全是两个不同的概念。
关于并发 并行 同步 异步 多线程的区别:
http://blog.csdn.net/cqkxboy168/article/details/9026205
捎带提一下 线程安全和非线程安全
线程安全就是在多线程环境下也不会出现数据不一致,而非线程安全就有肯能出现数据不一致
线程安全的类由于要确保线程安全增加了一定的开销,所以在单线程环境中效率没非线程安全的类效率高
原子和非原子属性的选择
nonatomic和atomic对比
atomic:线程安全,需要消耗大量的资源
nonatomic:非线程安全,适合内存小的移动设备
iOS开发的建议
所有属性都声明为nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力
我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等等问题,所以我们需要给线程加一个线程锁。线程锁的使用格式是:@synchronized(锁对象) { // 需要锁定的代码 }锁定1份代码只用1把锁,用多把锁是无效的。