多线程1
- 进程:
- 概念:系统中正在运行的一个应用程序
- 特点:每个进程都是独立的,运行在自己独有的且受保护的内存空间中。
- 线程:
- 概念:执行进程的单位,依赖于进程而存在
- NSThread创建线程的四种方法:
方法1
NSThread *threadC = [[NSThread alloc]initWithTarget:self selector:@selector(run:) object:@"创建线程1"];
方法2
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"分离一条子线程"];
方法3
[self performSelectorInBackground:@selector(run:) withObject:@"创建后台线程"];
方法4(自定义)
[[[NSThread alloc]init]start];
- 进程和线程的比较
- 进程是cpu分配资源和调度的单位
- 线程是cpu进行调度的最小单元
- 一个正在运行的应用程序只能有一个进程,一个进程有不少于一个线程
- 同一个进程内的线程共享进程的资源
- 多线程:
- 原理:cpu分时快速在各个线程之间切换调用
- 优缺点:
- 优点:提高程序的执行效率以及内存和cpu的利用率
- 缺点:开线程会耗费资源,尤其是大量开线程的情况,并且会是程序设计更加复杂
- 主线程:
- 概念:程序运行自动开启的线程(主线程或UI线程)
- 作用:显示刷新UI界面、处理UI事件
- 注意点: 主线程不宜执行耗时较长的操作
- 线程安全问题小结:
- 售票员实例:
// 创建三个售票员线程,让三个售票员分时抢占资源
self.totalSize = 100;
self.obj = [[NSObject alloc]init];
//创建线程
self.threadA = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
[self.threadA setName:@"售票员A"];
self.threadB = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
[self.threadB setName:@"售票员B"];
self.threadC = [[NSThread alloc]initWithTarget:self selector:@selector(saleTicket) object:nil];
[self.threadC setName:@"售票员C"];
//开始执行
[self.threadA start];
[self.threadB start];
[self.threadC start];
// 让售票员分时抢占资源
-(void)saleTicket
{
while (1) {
@synchronized(self) {
NSInteger count = self.totalSize;
if (count >0) {
for (NSInteger i = 0; i<10000000; i++) {
//演示耗时操作
}
//检查余票的数量,如果发现有余票就卖出去一张
self.totalSize = count - 1;
NSLog(@"%@卖出去了一张,还剩下%zd张票",[NSThread currentThread].name,self.totalSize);
}else
{
NSLog(@"不要回家的,或者做飞机回去吧");
break;
}
}
}
}
- 线程间通讯(下载图片实例):
- 注意图片设置一定要放到主线程中:
//1.确定url
NSURL *url = [NSURL URLWithString:@"http://img4.duitang.com/uploads/blog/201310/18/20131018213446_smUw4.thumb.700_0.jpeg"];
//2.下载图片的二进制数据到本地
NSData *data = [NSData dataWithContentsOfURL:url];
//3.转换格式 二进制数据转换UIimage
UIImage *image = [UIImage imageWithData:data];
NSLog(@"%@---",[NSThread currentThread]);
//4.回到主线程刷新UI
[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:NO];
[self performSelector:@selector(showImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:YES];
[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];
//获得的时间是绝对时间
CFTimeInterval start = CFAbsoluteTimeGetCurrent();
- 线程的状态(创建、开启、运行、阻塞、死亡):
[NSThread sleepForTimeInterval:2.0];
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:10.0]];
[NSThread exit]
- GCD的使用(重点):
- 重要概念(队列是GCD中的概念):
- 并发队列(并发队列):允许多个任务同时执行
- 串行队列(主队列):多个任务依次执行,其中主队列必须在主线程中执行,当需要任务调度时首先检查主线程状态,若主线程阻塞,则停止调动
- 同步:必须得到该方法的返回值才能往下执行
- 异步:不必得到该方法的返回值依然可以向下执行
- 队列:(用来存放任务)
- 并发队列:(允许多个队列同时执行):
1)直接create dispatch_queue_create
2)全局并发队列
- 串行队列:(任务串行执行)
1)直接create dispatch_queue_create
2)主队列:
1)所有在主队列中的任务都会被放在主线程中执行
2)主队列中的任务在执行之前会先检查主线程的状态, 如果发现主线程当前正在执行任务那么会暂停队列中任务的调度- 队列与函数组合是否开线程以及开几条线程:
- 异步函数+主队列:不会开线程,所有的任务串行执行
//1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.封装任务
dispatch_async(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
//1.获得主队列
dispatch_queue_t queue = dispatch_get_main_queue();
//2.封装任务
dispatch_sync(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_queue_t queue = dispatch_queue_create("com.seemygo.www.download", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_queue_t queue = dispatch_queue_create("com.seemygo.www.download", DISPATCH_QUEUE_CONCURRENT);
dispatch_sync(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
dispatch_queue_t queue = dispatch_queue_create("com.seemygo.www.download", DISPATCH_QUEUE_SERIAL);
dispatch_sync(queue, ^{
NSLog(@"1---%@",[NSThread currentThread]);
});
- GCD线程间通信:
//1.开线程下载图片
//DISPATCH_QUEUE_PRIORITY_DEFAULT 0
dispatch_async(dispatch_get_global_queue(0, 0), ^{
NSLog(@"%@----",[NSThread currentThread]);
//1.1 确定url
NSURL *url = [NSURL URLWithString:@"http://img4.duitang.com/uploads/blog/201308/24/20130824215734_ut8LZ.thumb.600_0.jpeg"];
//1.2 下载二进制数据到本地
NSData *data = [NSData dataWithContentsOfURL:url];
//1.3 转换图片
UIImage *image = [UIImage imageWithData:data];
//刷新UI
dispatch_sync(dispatch_get_main_queue(), ^{
self.imageView.image = image;
NSLog(@"%@--UI--",[NSThread currentThread]);
});
});
- GCD中常用函数:
1.方法
[self performSelector:@selector(task) withObject:nil afterDelay:2.0];
2.方法
[NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(task) userInfo:nil repeats:NO];
3.方法
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_global_queue(0, 0), ^{
NSLog(@"--GCD----%@",[NSThread currentThread]);
});
// 整个应用程序只会执行一次,并且是线程安全的
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"--once---%@",[NSThread currentThread]);
});
1.在子线程中,确保前面任务执行完才会执行后面线程
dispatch_barrier_async(queue, ^{
NSLog(@"+++++++++++++%@",[NSThread currentThread]);
});
- 快速迭代函数
//注意:主线程也会参与迭代的过程,里面的任务是并发执行的
!!!!不能传主队列
dispatch_apply(10, queue, ^(size_t index) {
NSLog(@"%zd---%@",index,[NSThread currentThread]);
});
网友评论