提到线程,就不得不说什么是进程。进程是:一个程序在一个数据集合上的一次运行。这句话也就是说,一个进程,是一个程序在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];
//创建操作队列
NSOperationQueue *quene=[[NSOperationQueuealloc]init];
//设置队列的最大操作数--(并行执行 )
quene.maxConcurrentOperationCount=10;
//第一种 NSInvocationOperation
NSInvocationOperation *operation=[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(doThing1)object:nil];
//将操作加入到队列中
[queneaddOperation:operation];
//第二种 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");
});
<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>
<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];主线程