提到线程,就不得不说什么是进程。进程是:一个程序在一个数据集合上的一次运行。这句话也就是说,一个进程,是一个程序在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];
//第三中自定义操作
/**
自定义操作,由于是继承自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>
<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.
第一种 使用线程队列,有两个步骤,
第一步:创建线程队列
第二步:异步执行线程队列
第二种 使用线程组(常用,当线程组中,可以有通知主线程的方法),有三个步骤
第一步:创建线程组
第二步:创建线程队列
第三步:将线程队列放到线程组种,异步执行线程组
第一种方式: 线程队列
//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];主线程