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

iOS -- 线程 还有待补全--(关于线程死锁,解决办法等。。)(NSThread、NSOperation、GCD) -- ASI/AFNetWork

2014-12-22 17:17 567 查看
提到线程,就不得不说什么是进程。进程是:一个程序在一个数据集合上的一次运行。这句话也就是说,一个进程,是一个程序在CPU中运行的体现。线程是进程的具体实现,也就是说,一个进程在CPU中进行时间片轮转,真正轮转执行的时一个进程的线程。

进程是系统进行资源分配和调度的一个独立单位。

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.

一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

线程是处理器调度的基本单位

开启多线程,在iOS中有三种方法开启多线程

1:NSThread
最接近底层 但是这种线程是不安全的

(因为线程可抢夺,当一个线程先访问了外部变量,在对其进行操作,过了一会,另一个优先级别更高的线程开启了,它也需要使用到同一个外部变量,对它操作完后,这是第一次使用这个外部变量的线程再次使用这个外部变量,就会发生预想不到的错误)。解决办法,就是加锁。线程中还容易发生死锁,这个问题,编者以后补上。

2:NSOperation
更好用,线程安全

3:GCD 和NSOperation一样,更好用,线程安全

第一种 NSThread

开辟线程 有对象方法和类方法

a :对象方法 创建子线程:

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

//线程名字
thread.name=@"休眠1s";

//线程优先级
thread.threadPriority=0.5;
[threadstart];

b :类方法 创建子线程

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

使用NSThread创建的子线程,返回子线程的方法:

//返回主线程中执行执行 --- func

[selfperformSelectorOnMainThread:@selector(func)withObject:nilwaitUntilDone:NO];

第二种
NSOperation

步骤:01:创建一个操作队列。

//创建操作队列

NSOperationQueue *quene=[[NSOperationQueuealloc]init];

//设置队列的最大操作数--(并行执行
)

quene.maxConcurrentOperationCount=10;
02 :创建操作,将其加入到操作队列中。

创建操作,又有三种方法:
a:NSInvocationOperation

//第一种 NSInvocationOperation

NSInvocationOperation *operation=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doThing1)object:nil];

//将操作加入到队列中
[queneaddOperation:operation];

b:
NSBlockOperation

//第二种 NSBlockOperation

NSBlockOperation *blockOperation=[NSBlockOperationblockOperationWithBlock:^{
[selfthird];
}];
[queneaddOperation:blockOperation];

c: 自定义一个操作,继续自NSOperation

//第三中自定义操作
/**

自定义操作,由于是继承自NSOperation,所以我们可以在自定义操作中,设置成员变量,或属性,方法。这样的话,逻辑更 加清晰。

*/

AZMyOperation *myOperation=[[AZMyOperationalloc]init];
[queneaddOperation:myOperation];

// [NSOperationQueue mainQueue];主线程

附:AZMyOperation

<span style="font-size:14px;">#import <Foundation/Foundation.h>

@interface AZMyOperation : NSOperation

@end</span>


<span style="font-size:14px;">#import "AZMyOperation.h"

@implementation AZMyOperation

//操作的入口函数
-(void)main
{
NSLog(@"自定义操作");

}

@end</span>


附: NSThread 和 NSOperation 的小demo
<span style="font-size:14px;">#import "AZViewController.h"
#import "AZMyOperation.h"
@interface AZViewController ()

@end

@implementation AZViewController

- (void)viewDidLoad
{
[super viewDidLoad];

/*
刷新UI操作,必须在主线程中进行

开启多线程,在iOS中有三种方法开启多线程

1:NSThread            最接近底层   但是这种线程是不安全的
2:NSOperation       更好用,线程安全
3:GCD                    和NSOperation一样,更好用,线程安全

*/

[self createNSThread];

//第二种
[self createNSOperation];

}

-(void)createNSThread
{
UIButton *btn =[UIButton buttonWithType:UIButtonTypeSystem];
btn.frame=CGRectMake(10, 40, 300, 20);
[btn setTitle:@"开启线程-- NSThread" forState:UIControlStateNormal];

[btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];
}
-(void)createNSOperation
{
UIButton *btn =[UIButton buttonWithType:UIButtonTypeSystem];
btn.frame=CGRectMake(10, 100, 300, 20);
[btn setTitle:@"开启线程-- NSNSOperation" forState:UIControlStateNormal];

[btn addTarget:self action:@selector(btnOperationClick:) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:btn];

}
-(void)btnClick:(UIButton *)btn
{
#if 0
//休眠主线程,可以看到只有当休眠2s后,btn的高亮才会消失,这既是,刷新UI操作,都是在主线程中完成的。
[self first];
[self second];

#endif

//开辟子线程  对象方法、类方法

//对象方法 创建子线程
NSThread *thread=[[NSThread alloc] initWithTarget:self selector:@selector(doThing) object:nil];
//线程名字
thread.name=@"休眠1s";
//线程优先级
thread.threadPriority=0.5;
[thread start];

//类方法 创建子线程
[NSThread detachNewThreadSelector:@selector(doThing1) toTarget:self withObject:nil];

}
#pragma mark -- 队列响应
-(void) btnOperationClick:(UIButton *)btn
{
//创建操作队列
NSOperationQueue *quene=[[NSOperationQueue alloc] init];

//设置队列的最大操作数--( 并行执行 )
quene.maxConcurrentOperationCount=10;

/*
//创建操作
//有三种方式
1:NSInvocationOperation
2:NSBlockOperation
3:  自定义操作
*/

//第一种  NSInvocationOperation
NSInvocationOperation *operation=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doThing1) object:nil];

//将操作加入到队列中
[quene addOperation:operation];

//第二种  NSBlockOperation
NSBlockOperation *blockOperation=[NSBlockOperation blockOperationWithBlock:^{
[self third];
}];
[quene addOperation:blockOperation];

//第三中 自定义操作
/**
自定义操作,由于是继承自NSOperation,所以我们可以在自定义操作中,设置成员变量,或属性,方法。这样的话,逻辑更加清晰。
*/
AZMyOperation *myOperation=[[AZMyOperation alloc] init];
[quene addOperation:myOperation];
}

-(void)doThing
{
[self first];

//返回主线程中执行执行  ---  func
[self performSelectorOnMainThread:@selector(func) withObject:nil waitUntilDone:NO];

[self second];
}
-(void)doThing1
{
[self second];
}
-(void)first
{
//休眠主线程
sleep(1);
NSLog(@"1");
}
-(void)second
{
sleep(2);
NSLog(@"2");
}
-(void)third
{
sleep(3);
NSLog(@"3");
}

-(void)func
{
NSLog(@"主线程执行:子线程已经结束");
}
@end</span><span style="font-size: 18px;">
</span>


第三种 GCD

有两种方式实现GCD.

第一种
使用线程队列,有两个步骤,

第一步:创建线程队列

第二步:异步执行线程队列

第二种
使用线程组(常用,当线程组中,可以有通知主线程的方法),有三个步骤

第一步:创建线程组

第二步:创建线程队列

第三步:将线程队列放到线程组种,异步执行线程组

第一种方式:
线程队列

//01
创建线程队列
dispatch_queue_t thread=dispatch_queue_create(NULL,
NULL);

//02
异步执行线程队列(也就是在,在这个线程队列中,要做什么事)
dispatch_async(thread, ^{
sleep(2);
NSLog(@"休眠2s");
});

//也可以通过 dispatch_get_global_queue(0, 0)
得到闲置的线程队列,如果没有,则会自动创建一个现场队列。

dispatch_async(dispatch_get_global_queue(0,
0), ^{
sleep(2);
NSLog(@"休眠2s");
});

第二种方式:线程组

//01
创建线程组

dispatch_group_t threadGroup=dispatch_group_create();

//02
创建线程队列

dispatch_queue_t t=dispatch_queue_create(NULL,
NULL);

//03
将线程队列放入到线程组中,

dispatch_group_async(threadGroup, t, ^{

sleep(2);

NSLog(@"休眠2s");
});

//这里又可使用闲置线程队列

dispatch_group_async(threadGroup,
dispatch_get_global_queue(0,
0), ^{

sleep(2);

NSLog(@"休眠2s");
});

/*

使用线程组有一个好处就是
当线程组的线程队列已经全部执行完毕后 可以通知
主线程

*/

dispatch_group_notify(threadGroup,
dispatch_get_main_queue(), ^{

NSLog(@"线程组的线程队列已经全部执行完毕。回到主线程");
});

//验证
是否是线程组中的线程队列全部执行完毕后,才调用 通知的

//经过验证
的确是当线程组中的线程队列全部执行完毕后,才开始 通知

dispatch_group_async(threadGroup,
dispatch_get_global_queue(0,
0), ^{

sleep(3);

NSLog(@"休眠3s");
});

那么在第三方框架中是怎么来使用线程的呢??
ASI:
<span style="font-size:14px;">ASINetworkQueue* queue = [[ASINetworkQueue alloc] init];
queue.maxConcurrentOperationCount = 1;
for (int i = 0; i < 5; i++) {
ASIHTTPRequest* request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:@"http://10.0.8.8/my/sns/user_list.php"]];
[queue addOperation:request];
}
[queue go];

NSURLRequest* request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://10.0.8.8/my/sns/user_list.php"]];
NSOperationQueue* operationQueue = [[NSOperationQueue alloc] init];
//发送一个异步请求
[NSURLConnection sendAsynchronousRequest:request queue:operationQueue completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

}];</span><span style="font-size: 18px;">
</span>


AFNetWork:

<span style="font-size:14px;"> NSURLRequest *request=[NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www.baidu.com/img/bdlogo.png"]];
_operation=[[AFHTTPRequestOperation alloc] initWithRequest:request];

[_operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(@"成功");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(@"失败");
}];

//设置保存路径
NSString *path=[NSString stringWithFormat:@"%@/Documents/a.png",NSHomeDirectory()];
NSLog(@"%@",path);

//设置操作输出流
_operation.outputStream=[NSOutputStream outputStreamToFileAtPath:path append:NO];

__weak UIProgressView *PV=self.progress;

//设置下载进度
[_operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
#if 0
[self.progress setProgress:(float)totalBytesRead/totalBytesExpectedToRead animated:YES];
#endif
//注意在block中有警告的话,可以在外面
//__weak UIProgressView *PV=self.progress;
[PV setProgress:(float)totalBytesRead/totalBytesExpectedToRead animated:YES];
}];

//开始操作
[_operation start];
</span>


// [NSOperationQueue mainQueue];主线程
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: