iOS提供了三种多线程的技术:NSThread;GCD;
NSOperation和NSOperationQueue;
1.使用NSThread创建多线程:
创建NSThread线程有实力方法和类方法两种方法
- (void)viewDidLoad {
//创建NSThread线程有实例方法和类方法两种方法
//实例方法创建线程对象
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(show) object:nil];
[thread start];
//通过类方法创建线程
[NSThread detachNewThreadSelector:@selector(show) toTarget:self withObject:nil];
}
-(void)show
{
NSLog(@"%@",[NSThread currentThread]);
}
调用实例方法创建线程返回一个thread对象,因此必须还要调用一下start方法启动线程,而调用类方法可以直接创建并启动线程。无论类方法还是实力方法本质上都是通过观察者模式,调用target对象的selector方法,作为线程的执行体,执行结果如下:
2016-04-25 10:56:36.842 ios三种多线程[1767:96781] <NSThread: 0x7f9bb260db80>{number = 3, name = (null)}
2016-04-25 10:56:36.842 ios三种多线程[1767:96780] <NSThread: 0x7f9bb27162f0>{number = 2, name = (null)}
可以看到程序产生了number分别为2和3的新线程,这是因为number为1的是主线程。在NSlog语句中,currentThread方法是查看当前线程对象。
线程进入睡眠状态时,不会获得执行的机会:
//让线程进入睡眠状态
[NSThread sleepForTimeInterval:0.5];
线程的优先级:
线程的优先级在0.0~1.0之间,优先级高获会的更多的执行机会,线程默认优先级为0.5
//设置线程的优先级为最高
thread.threadPriority = 1.0;<span style="font-size:18px;"><strong>
</strong></span>
使用@synchronized实现线程同步:
@synchronized(self) //括号内为同步监视器,表示同步代码运行前必须先获得同步监视器的锁定
{
//需要同步的代码块
}//释放同步锁,为了保证线程访问安全,在任何线程修改指定资源时都要对该资源进行锁定,锁定期间其它线程不得修改。<span style="font-size:18px;">
</span>
使用NSLock实现线程同步:
使用NSLock相当于同步监视器为NSLock对象,每次只有一个线程能对NSLock加锁
NSLock *lock ;
[lock lock];
//需要同步的代码
[lock unlock];
2.使用GCD实现多线程:
相对于要手动管理线程同步安全的NSThread方法,GCD则要简单得多;
GCD的一大优势就是充分利用CPU的内核,让双核、四核的CPU更高效的工作;
GCD的核心是队列,使用GCD来实现多线程只需要创建队列,并把任务放在队列中处理。GCD的队列类型如下:
(1)主队列:dispatch_get_main_queue()
所有添加到主队列的任务都是在主线程中执行的;
(2)全局队列:
dispatch_get_global_queue()
全局队列也叫并发队列,所有添加到全局队列中的任务都是并发执行,可能会开启多个线程;
(3)串行队列:dispatch_queue_create()
串行队列中所有的任务都按顺序执行,只开一条线程;
除了队列,GCD中还有同步与异步两种提交任务的方式,同步还是异步取决于方法名,与是什么样的队列没有关系
同步:dispatch_sync 在当前线程执行任务不会开启新的线程
异步:dispatch_async 在当前线程执行任务会开启新的线程
使用GCD下载网络图片的例子
//使用GCD下载网络图片:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//通过异步的全局队列下载图片
NSString *url = @"http://img5.imgtn.bdimg.com/it/u=1179777510,2740895801&fm=21&gp=0.jpg";
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:data];
//下载图片完成后在主线程中更新UI界面
if(image != nil)
{
dispatch_async(dispatch_get_main_queue(), ^{
_imageView.image = image;
});
}
else
{
NSLog(@"图片下载失败");
}
});
用GCD实现执行完线程p1,p2后在执行p3线程:
把p1,p2放到dispatch group中,再和p3用串行队列;
3.使用NSOperation与NSOperationQueue实现多线程:
NSOperation和NSOperationQueue相对于GCD来说更加的面向对象,同时它可以控制最多线程的数量,并且可以控制线程执行的顺序。使用步骤同样是先创建NSOperation,然后把NSOperation添加到NSOperationQueue中。
NSOperation中通过maxConcurrentOperationCount来控制最多的子线程数量,通过addDependence控制线程先后执行的顺序;
使用NSOperation下载网络图片的例子
//使用NSOperation下载网络图片
NSOperationQueue *_queue = [[NSOperationQueue alloc] init];
//设置线程的最大数量为2
_queue.maxConcurrentOperationCount = 2;
NSString *url = @"http://img5.imgtn.bdimg.com/it/u=1179777510,2740895801&fm=21&gp=0.jpg";
NSOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
UIImage *image = [[UIImage alloc] initWithData:data];
if (image != nil) {
//在主线程中执行更新UI的方法
[self performSelectorOnMainThread:@selector(updateUI) withObject:image waitUntilDone:YES];
}
}];
NSOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"执行线程op2");
}];
//将NSOperation添加到NSOperationQueue中
[_queue addOperation:op1];
[_queue addOperation:op2];
//op1执行完毕之后才能执行op2
[op2 addDependency:op1];