您的位置:首页 > 产品设计 > UI/UE

UI:多线程 、用GCD创建线程

2015-10-07 09:54 513 查看
什么是应用(程序):就是我们编写的代码编译后生成的app文件

进程:凡是一个运行的程序都可以看作为一个进程,如打开的多个 word,就可以认为是一个进程的多个线程。

线程:至少有一个线程就是主线程,网络的异步请求就是多线程的应用。程序中我们写的代码段。单线程容易出现阻塞,程序的假死。多线程就不会出现这样的情况。

理解实例:一个餐厅的运营。餐厅的所有资源(电脑,菜,桌椅,地点,调料)的组合,就是一个程序的进程、(服务员,收银员,后厨)就是线程、程序的运行时靠线程(程序的代码块)的执行。

开辟子线程方式:

第一种:系统的写法

NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(printf) object:nil];

[thread start];//需要我们手动的开启线程,可以在程序的某些地方选择的开启线程

第二种:自动的开启线程,调用一个自身的类方法

[NSThread detachNewThreadSelector:@selector(printf) toTarget:self withObject:nil];

用户自己在程序的运行的某处要执行一个要执行很久的程序,但是不能让整个程序阻塞,就需要开辟一个线程。UI涮新,网络请求,点击事件是主线程要做的。

两种方法的区别,第一种必须手动的去调用。

栈区开辟的大小是1M主线程,我们自己开辟的子线程是512K,子线程是在主线程下执行。

(http://blog.csdn.net/echoisland/article/details/6403763 堆、栈、线程之间的关系)线程依赖于程序(进程),进程运行时内存是独立分配的,多线程运行的时候是共享内存。多线程的意义在于,通过进程管理线程让程序的不同功能块能够同时的进行运行,提高程序的运行效率。进程是某个具有独立功能的程序在一个数据集合上的一次运行,进程是操作系统进行调度和资源分配的独立单位。线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

堆:分为局部堆 和全局堆,前者是进程所分配得到的内存空间,后者就是所有没有分配的内存空间,局部堆使用完毕后要归还给操做系统,不然就是内存泄露。

栈:是线程独有的,(在高级语言中)不需要在程序的运行期间进行释放,用于在程序的运行期间保护程序线程的运行状态和局部变量,在线程运行的时候进行初始化。

堆和栈的区别可以用如下的比喻来看出:
使用栈就象我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。
使用堆就象是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

《主要看API文档学习方法》

线程的优先级,threadPriority 返回值是double (0.0-1.0)之间,1.0就是最先执行的线程

研究系统的编码写法(对于分类、以及定义的方法)

所有的线程(主线程、子线程)都要有一个自动释放池,要及时的自动清理。

对于耗时的任务可以交给子线程,而界面的刷新界面上用户的交互,点击事件,必须有主线程来处理。子线程中系统是不会自动生成一个自动释放池,所以需要我们手动添加一个自动释放池

同步请求与异步请求忘记了?????

//网络请求的知识回顾

NSString * str = @"";

NSURL * Url = [NSURL URLWithString:str];

NSURLRequest * request = [NSURLRequest requestWithURL:Url];

// NSURLConnection 可以发起同步的,异步的请求

NSData * data =[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];//发起一个同步请求

UIImage * image = [UIImage imageWithData:data];

系统的多线程的开辟方法

#pragma mark (.h文件)--------------------------------------------------------------------------------------------------------

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UIButton *but1;
@property (weak, nonatomic) IBOutlet UIButton *but2;

@end

#pragma mark (.m文件)--------------------------------------------------------------------------------------------------------

#import "ViewController.h"

/*
1.多线程的GCD 的效率是最高的,要好好掌握
2.对象一般都定义成属性  retain 保证对对象拥有所有权,如果UITableView 的数据源定义的时候,定义成实例变量,就会刷不出页面数据。尽管其他的代码都很正确
3.系统的写法 1.需要手动的开启线程,可把线程定义成属性,控制进程的开关
4.线程的互斥问题,就是当一个线程在访问的一块资源的时候,另一个线程也要对这块资源进行访问。出现访问的冲突这就是线程的互斥,解决线程的互斥,可以为线程添加一个线程锁,当一个线程在访问资源的时候,把线程上锁,这样另一个线程就处于等待访问资源状态,当访问资源访问结束的时候,再把线程锁打开,这样就保证了另一个线程能够访问数据。
5.线程死锁,在解决线程互斥问题的时候,我们在第一个线程访问资源的时候,为线程添加了线程锁,但是在访问完数据之后并没有为线程锁开锁,这样就造成了另一个线程不能访问资源的情况,这就是线程的死锁。
6.   [NSThread currentThread];获得当前的线程
[NSThread isMainThread];获得主线程
7.    NSThread * thread = [[NSThread alloc] initWithTarget:self selector:@selector(handle) object:self];系统开启子线程,他需要我们手动去开启线程
*/

@interface ViewController ()
{
NSInteger totalTickets;//总票数   实例变量记录票数
}
@property(nonatomic,retain)NSLock * lock;
@end

@implementation ViewController
//按钮1
- (IBAction)but1:(id)sender {

#pragma mark---系统 init 方法
//这种写法程序仍然只有一个线程就是程序的主线程,程序运行默认生成的线程
NSLog(@"使用的线程是:%@",[NSThread currentThread]);
//系统的写法 1.需要手动的开启线程,可把线程定义成属性,控制进程的开关
NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(printf:) object:@"系统方法开启子线程"];
[thread start];
#pragma mark---NSObject 方法创建线程
//创建一个后台运行的子线程
[self performSelectorInBackground:@selector(printf:) withObject:@"NSObject 的主线程调用子线程后台执行"];
//在主线程去执行一个方法
[self performSelector:@selector(handle ) withObject:self withObject:@"子线程传入参数,就是前面方法的参数"];
}

-(void)printf:(NSString *)str{
@autoreleasepool {
NSLog(@"%d %@ %@",[NSThread isMainThread],[NSThread currentThread],str);
}
}
//按钮2
- (IBAction)but2:(id)sender {
#pragma mark----NSThread调用一个自身的类方法开启线程
//自动的开启线程,调用一个自身的类方法,内部已经封装了一个子线程
//withObject 就是 执行方法要传的参数
[NSThread detachNewThreadSelector:@selector(printf:) toTarget:self withObject:@"123"];
//下载图片的任务交给子线程来完成
[self performSelectorInBackground:@selector(downLoadImage) withObject:nil];
}
//分段控件
- (IBAction)segment:(id)sender {
}
#pragma mark---页面加载出来要执行的函数
- (void)viewDidLoad {
[super viewDidLoad];
totalTickets = 50;
self.lock =  [[NSLock alloc]init];//如果把这一句放到下面就会在控制台出现异常
[self viewDidLoad2];
}

-(void)downLoadImage{
#pragma mark----网络请求的知识回顾
/*
NSString * str = @"";
NSURL * Url = [NSURL URLWithString:str];
NSURLRequest * request = [NSURLRequest requestWithURL:Url];
// NSURLConnection 可以发起同步的,异步的请求
NSData * data =[NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];//发起一个同步请求
UIImage * image = [UIImage imageWithData:data];
*/
@autoreleasepool {
UIImage * image = [UIImage imageWithData:[NSData  dataWithContentsOfURL:[NSURL URLWithString:@"图片请求网址"]]];//内部封装的是一个同步的请求(思考内部封装的4个过程)
//返回主线程,进行界面的刷新操作
[self performSelectorOnMainThread:@selector(refreashUI:) withObject:image waitUntilDone:YES];
//waitUntilDone 参数什么意思

#pragma mark----NSOperationQueue 操作线程队列
//NSOperationQueue 操作队列,我们常使用他的子类,来具体的执行实际的任务,
//实际任务是由 NSOperation 的子类(NSInvocationOperation ,NSBlockOperation)来是实现
//任务1  NSInvocationOperation
NSInvocationOperation * op1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printf:) object:@"OP1任务"];
//任务2
NSInvocationOperation * op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadImage) object:@"OP2任务"];
//把上面的任务放到操作队列,任务对列会为队列中的任务合理的安排子线程去完成任务(并不是按照添加的顺序执行)
NSOperationQueue * quene = [[NSOperationQueue alloc]init];
[quene addOperation:op1];
[quene addOperation:op2];

#pragma mark----NSBlockOperation 创键任务
//任务1 NSBlockOperation 创键任务
NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"我是 NSBlockOperation 创建任务");
}];
//任务2
NSBlockOperation * op4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"我是 NSBlockOperation 创建任务");
}];
NSOperationQueue *  quene2 = [[NSOperationQueue alloc]init];
[quene2 addOperation:op3];
[quene2 addOperation:op4];
//完成任务机制:例如我们有8 个子任务,所谓的合理安排就是,某个任务完成之后,操作队列就会把下一个没有执行的任务放到这一个已经完成任务的线程
//设置线程的最大的并发数目(就是一起执行任务的数目,实行线程的同步也可一说成是并发),对于网络请求有同步 异步 对于线程有 并发(任务同一时间同时执行) 与 串行(一个任务完后才执行下一个任务)
//        quene2.maxConcurrentOperationCount = 1;//默认是 - 1就是不限制的意思
//上面代码注释掉,任务的执行顺序与放的顺序无关
//设置任务之间的依赖关系 比如:第二个任务必须依赖于第一个任务先完成 我们要位第二个任务添加一个依赖
[op3 addDependency:op4];//op3必须依赖于 op4先完成

}
}
//刷新界面主线程的操作任务:刷新UI,处理用户交互
-(void)refreashUI:(UIImage *)image{
//可以去设置图片
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];

}

/*
买票系统
*/
-(void)viewDidLoad2{
totalTickets = 50;//初始化票数 50 张
//窗口1
[self performSelectorInBackground:@selector(sellTicket:) withObject:@"小明"];

//窗口2
[self performSelectorInBackground:@selector(sellTicket:) withObject:@"小刚"];
}

-(void)sellTicket:(NSString *)name{
@autoreleasepool {
while (YES) {
//加锁
[self.lock lock];
if (totalTickets > 0) {
totalTickets--;
NSLog(@"%@ 卖完了,现在剩余的票数是:%ld",name,totalTickets);
}else{
NSLog(@"%@ 卖完了",name);
break;
}
[self.lock unlock];//解锁
}
}
}

@end


View Code ViewController文件

在一个程序中开辟的同步线程不能过多,过多容易造成假死,所以能用异步线程就用异步线程。

//串行队列

- (IBAction)chuanxingduilei:(id)sender {

dispatch_queue_t queue1 = dispatch_queue_create("niu", DISPATCH_QUEUE_SERIAL);

dispatch_sync(queue1, ^{

self.imagView.backgroundColor = [UIColor redColor];

isYes =YES;

[self text:@"queue1"];

});

// dispatch_queue_t queue2 = dispatch_get_main_queue();

// dispatch_sync(queue2, ^{

// [self text:@"main thread"];

// });

}

//并行队列

- (IBAction)bingxingduilei:(id)sender {

dispatch_queue_t queue1 = dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

dispatch_async(queue1, ^{

[self text:@"bingxing"];

isYes = NO;

});

dispatch_async(queue1, ^{

[self text:@"bingxing"];

isYes = YES;

});

dispatch_async(queue1, ^{

[self text:@"bingxing"];

isYes = NO;

});

}

//分组

- (IBAction)group:(id)sender {

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{

[self text:@"分组"];

});

}

//重复

- (IBAction)chongfu:(id)sender {

dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_apply(5, queue, ^(size_t index) {

[self text:[NSString stringWithFormat:@"第%ld次",index]];

});

}

//一次

- (IBAction)oncetime:(id)sender {

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

[self text:@"only once"];

});

}

//障碍

- (IBAction)zhangai:(id)sender {

dispatch_queue_t queue = dispatch_queue_create("barrier", DISPATCH_QUEUE_CONCURRENT);

dispatch_async(queue, ^{

[self text:@"1写入文件"];

});

dispatch_async(queue, ^{

[self text:@"2写入文件"];

});

dispatch_async(queue, ^{

[self text:@"3写入文件"];

});

dispatch_barrier_async(queue, ^{

[self text:@"添加障碍"];

});

dispatch_async(queue, ^{

[self text:@"读文件1"];

});

dispatch_async(queue, ^{

[self text:@"读文件2"];

});

dispatch_async(queue, ^{

[self text:@"读文件3"];

});

}

//延迟

- (IBAction)yanchi:(id)sender {

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5.0*NSEC_PER_SEC)), queue , ^{

[self text:@"延迟5秒后执行"];

});

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0*NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

[self text:@"在主线程中延迟后2秒的时候执行"];

});

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