iPhone中的线程应用并不是无节制的,官方给出的资料显示,iPhoneOS下的主线程的堆栈大小是1M,第二个线程开始就是512KB,并且该值不能通过编译器开关或线程API函数来更改,只有主线程有直接修改UI的能力
Mac和IOS中的程序启动,创建好一个进程的同时,一个线程便开始运作,这个线程叫做主线程。主线成在程序中的位置和其他线程不同,它是其他线程最终的父线程,且所有的界面的显示操作即AppKit或UIKit的操作必须在主线程进行。
Cocoa operation相关的类是NSOperation, NSOperationQueue.
NSOperation是个抽象类,使用它必须用它的子类,可以实现它或者使用它定义好的两个子类:NSInvocationOperation和NSBlockOperation.
Grand Centraldispatch(GCD)是Apple开发的一个多核编程的解决方案。在iOS4.0开始之后才能使用。GCD是一个替代NSThread,NSOperationQueue,NSInvocationOperation等技术的很高效强大的技术。
kURL
@"http://www.iyi8.com/uploadfile/2014/0506/20140506085929652.jpg"
@interface ViewController : UIViewController
@end
#import
"ViewController.h"
@interface ViewController ()
{
UIImage *_image;
UIImageView *_imageView;
int _tickets;
int _count;
NSThread *_threadOne;
NSThread *_threadTwo;
NSThread *_threadThree;
NSCondition *_condition;
NSLock *_lock;
}
@end
@implementation ViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
}
28 return self;
29}
1- (void)loadView
2 {
3 self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
4 NSLog(@"klfaklfa ------ - - ");
5
6 _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 150)];
7 [self.view addSubview:_imageView];
8 }
1- (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 _tickets = 200;
6 _count = 0;
7 _lock = [[NSLock alloc] init];
8
9 //锁对象
10 _condition = [[NSCondition alloc] init];
11 //线程1
12 _threadOne = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
13 _threadOne.name = @"thread-1";
14 [_threadOne start];
15
16 //线程2
17 _threadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
18 _threadTwo.name = @"thread-2";
19 [_threadTwo start];
20
21 //线程3
22 _threadThree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];
23 _threadThree.name = @"thread-3";
24 [_threadThree start];
25
26 //如果没有线程同步的lock,物品售出数量就会出现重复导致数据竞争不同步问题.加上lock之后线程同步保证了数据的正确性。
27 [NSThread detachNewThreadSelector:@selector(downloadImage:) toTarget:self withObject:kURL];
28 NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:kURL];
29 [thread start];
30}
1- (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self
6 selector:@selector(downloadImage:)
7 object:kURL];
8
9 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
10 [queue addOperation:operation];
11}
第二种方式继承NSOperation
在.m文件中实现main方法,main方法编写要执行的代码即可。
如何控制线程池中的线程数?
队列里可以加入很多个NSOperation,可以把NSOperationQueue看作一个线程池,可往线程池中添加操作(NSOperation)到队列中。线程池中的线程可看作消费者,从队列中取走操作,并执行它。
通过下面的代码设置:
1[queue setMaxConcurrentOperationCount:5];
线程池中的线程数,也就是并发操作数。默认情况下是-1,-1表示没有限制,这样会同时运行队列中的全部的操作。
[html] viewplaincopy
1- (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
6 NSURL * url = [NSURL URLWithString:kURL];
7 NSData * data = [[NSData alloc]initWithContentsOfURL:url];
8 UIImage *image = [[UIImage alloc]initWithData:data];
9
10 if (data != nil) {
11 dispatch_async(dispatch_get_main_queue(), ^{
12 _imageView.image = image;
13 });
14 }
15 });
16}
(三)GCD的介绍和使用
介绍:
Grand Central Dispatch简称(GCD)是苹果公司开发的技术,以优化的应用程序支持多核心处理器和其他的对称多处理系统的系统。这建立在任务并行执行的线程池模式的基础上的。它首次发布在MacOS X 10.6 ,iOS 4及以上也可用。
设计:
GCD的工作原理是:让程序平行排队的特定任务,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务。
一个任务可以是一个函数(function)或者是一个block。GCD的底层依然是用线程实现,不过这样可以让程序员不用关注实现的细节。
GCD中的FIFO队列称为dispatch queue,它可以保证先进来的任务先得到执行。
dispatch queue分为下面三种:
Serial
又称为private dispatch queues,同时只执行一个任务。Serialqueue通常用于同步访问特定的资源或数据。当你创建多个Serial queue时,虽然它们各自是同步执行的,但Serialqueue与Serial queue之间是并发执行的。
Concurrent
又称为global dispatch queue,可以并发地执行多个任务,但是执行完成的顺序是随机的。
Main dispatchqueue
它是全局可用的serial queue,它是在应用程序主线程上执行任务的。
我们看看dispatch queue如何使用?
1、常用的方法dispatch_async
为了避免界面在处理耗时的操作时卡死,比如读取网络数据,IO,数据库读写等,我们会在另外一个线程中处理这些操作,然后通知主线程更新界面。
用GCD实现这个流程的操作比前面介绍的NSThread NSOperation的方法都要简单。代码框架结构如下
[html] viewplaincopy
1- (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 //此方法可以实现监听一组任务是否完成,如果完成后通知其他操作(如界面更新),此方法在下载附件时挺有用,
6 //在搪行几个下载任务时,当下载完成后通过dispatch_group_notify通知主线程下载完成并更新相应界面
7 dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
8 dispatch_group_t group = dispatch_group_create();
9 dispatch_group_async(group, queue, ^{
10 [NSThread sleepForTimeInterval:0.09];
11
12 NSLog(@"group1");
13 NSURL * url = [NSURL URLWithString:kURL];
14 NSData * data = [[NSData alloc]initWithContentsOfURL:url];
15 _image = [[UIImage alloc]initWithData:data];
16
17 });
18 dispatch_group_async(group, queue, ^{
19 [NSThread sleepForTimeInterval:0.09];
20 NSLog(@"group2");
21 });
22 dispatch_group_async(group, queue, ^{
23 [NSThread sleepForTimeInterval:0.09];
24 NSLog(@"group3");
25 });
26
27 dispatch_group_notify(group, dispatch_get_main_queue(), ^{
28 NSLog(@"updateUi");
29
30 _imageView.image = _image;
31 });
32}
[html] viewplaincopy
1- (void)viewDidLoad
2 {
3 [super viewDidLoad];
4
5 //是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
6 dispatch_queue_t queue = dispatch_queue_create("gcd.devdiy.com", DISPATCH_QUEUE_CONCURRENT);
7 dispatch_async(queue, ^{
8 [NSThread sleepForTimeInterval:2];
9 NSLog(@"dispatch_async1");
10 });
11
12 dispatch_async(queue, ^{
13 [NSThread sleepForTimeInterval:4];
14 NSLog(@"dispatch_async2");
15 });
16
17 dispatch_barrier_async(queue, ^{
18 NSLog(@"dispatch_barrier_async");
19 [NSThread sleepForTimeInterval:4];
20 });
21
22 dispatch_async(queue, ^{
23 [NSThread sleepForTimeInterval:1];
24 NSLog(@"dispatch_async");
25 });
26}
[html] viewplaincopy
1- (void)run3
2 {
3 while (true) {
4 [_condition lock];
5 [NSThread sleepForTimeInterval:3];
6 NSLog(@"当前物品名称:%d,售出数量:%d,线程名-=-==: %@", _tickets, _count, [[NSThread currentThread] name]);
7
8 [_condition signal];
9 [_condition unlock];
10 }
11}
12
13- (void)run
14{
15 while (true) {
16 //上锁
17 [_lock lock];
18 if (_tickets > 0) {
19 [NSThread sleepForTimeInterval:0.09];
20 _count = 200 - _tickets;
21 NSLog(@"当前物品名称:%d,售出数量:%d,线程名: %@", _tickets, _count, [[NSThread currentThread] name]);
22 _tickets--;
23 }else{
24 break;
25 }
26
27 [_lock unlock];
28 }
29}
30
31
34- (void)downloadImage:(NSString *) url{
35 NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
36 UIImage *image = [[UIImage alloc] initWithData:data];
37 if(image == nil){
38 [self updateUI:image];
39 }else{
40 [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES];
41 }
42}
43
44- (void)updateUI:(UIImage *)image
45{
46 _imageView.image = image;
47}
48
49@end
是不是代码比NSThread NSOperation简洁很多,而且GCD会自动根据任务在多核处理器上分配资源,优化程序。
系统给每一个应用程序提供了三个concurrent dispatchqueues。这三个并发调度队列是全局的,它们只有优先级的不同。因为是全局的,我们不需要去创建。我们只需要通过使用函数dispath_get_global_queue去得到队列。
以上代码组织的不是很好,只简单描述了一下多线程的基本概念,后续我再添加详细应用的实例,现只做为参考,在具体实际应用中还得我们自己来进行编写发挥。希望对大家有所帮助和启发。