//
// ViewController.m
// UI-NO.24多线程-1
//
// Created by Bruce on 15/8/25.
// Copyright (c) 2015年 Bruce. All rights reserved.
//
/*
当用户下载资源、进行图像处理、耗时数据处理等任务时 往往希望操作这个任务的时候 其他的操作不会被中断 这时候 就用到了 多线程
在单线程中一个线程只能执行一个任务,一个任务处理不完另一个任务就不能开始,这样会影响用户体验 让用户感觉APP卡顿
现在苹果手机都是多核处理器,这样我们可以把一个任务分成多个步骤,在不要求顺序的情况下 使用多线程既能解决线程阻塞 增加用户体验又能充分利用多核处理器运行能力
每个应程序的内部,存在一个或多个执行线程,它同时或在一个几乎同时执行不同的操作
面试题:什么是进程?什么是线程?什么是多线程?
进程与线程:每个系统运行的程序都是一个进程,每个进程里面包含了一到多个线程
线程是一组指令的集合,程序中一个单一的顺序控制流程,是一个程序中,独立运行的程序片段(一个应用程序里面 单一的顺序控制执行的一个任务)
程序运行后,系统会创建一个叫做(main)主线程的线程,所有的UI控件都必须运行在主线程中,所以有人也叫它UI线程
如果将所有的任务都放在主线程中,容易造成UI阻塞
多线程:在同一个应用程序内,同时运行多个线程,完成不同的工作,叫做多线程
为什么要使用多线程:单线程的应用程序中,代码沿直线执行,只有前面的代码执行完了,才会去执行后面的代码,中间这段时间,实际上就处于等待状态。当用户执行某项操作,比如上传文件,或者下载文件,主线程会执行这个任务,直到上传结束后,主线程才能继续后面的工作,在这短时间内,主线程处于忙碌状态,不会对用户的请求做出任何反应,最直观的感受就是界面卡死,特别是操作这个任务需要大量的时间的时候就更为明显
既然单一的一个线程不能满足我们的需求,那我们就可以使用今天要讲的多线程进行操作,在用户需要上传或者下载文件的时候,开辟一个独立的线程,专门负责这个任务,这样两个线程就会并行去工作,主线程也就不用花费这么久去等待去更新界面了
当然,使用多线程有利有弊,多线程高效的背后是代码复杂程度的上升,需要管理线程之间的同步和互斥,需要协调线程间的通信,这就是我们常说的线程管理
在iOS中每个进程启动后都会建立一个主线程(UI线程),在iOS中除了主线程,其他子线程是独立于Cocoa Touch的
// iOS中有几种多线程方式
iOS中有三种多线程策略供开发者使用:NSThread、NSOperation(基类不可以直接使用 只能使用他的子类)、GCD(Grand Central Dispatch)
// GCD 苹果 推荐的一种 实现 多线程的方式
// 轻量级 :对系统框架的依赖性的程度
NSThread:是这三种策略里面相对轻量级的,需要自己去管理他的生命周期,以及线程之间的同步,线程共享同一应用程序的部分内存空间,他们拥有对数据相同的访问权限,所以得协调多个线程对同一数据的访问,常用的做法是在访问之前加锁,这会导致一定的性能开销
NSThread的创建和启动:
NSThread的创建主要有两种直接方式:
init
这种方式得手动去启动线程,虽然我们alloc init了 但是只有我们start的时候才会真正去创建去启动这个线程(这是一种延迟实现的思想)
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;
这种创建线程的方式,会立即开辟一个线程并启动线程
线程之间的通讯
performSelectorOnMainThread withObject:waitUntilDone:
更新主线程
performSelector:onThread:withObject:waitUntilDone:
更新指定子线程
解决 阻塞 主线程
*/
#import "ViewController.h"
@interface ViewController ()
{
UIImageView *pointView;
NSThread *newThread;
NSCondition *condition;
int ticketNum;
int count;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
/*
[NSThread detachNewThreadSelector:@selector(updata) toTarget:self withObject:nil];
// 这种创建线程的方式,会立即开辟一个线程并启动线程
NSLog(@"主线程");
*/
/*
newThread = [[NSThread alloc]initWithTarget:self selector:@selector(updata1) object:nil];
[newThread start];
NSLog(@"主线程");
// 这种方式得手动去启动线程,虽然我们alloc init了 但是只有我们start的时候才会真正去创建去启动这个线程(这是一种延迟实现的思想)
*/
/*
[self performSelectorInBackground:@selector(updata) withObject:nil];
NSLog(@"主线程");
// 这是一种隐式创建线程的方法,效果与第一种一样
*/
/*
线程之间的通讯
performSelectorOnMainThread withObject:waitUntilDone:
更新主线程
performSelector:onThread:withObject:waitUntilDone:
更新指定子线程
*/
// 线程同步 线程锁
// NSCondition
/*
ticketNum = 100;
condition = [[NSCondition alloc]init];
NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(act) object:nil];
thread1.name = @"thread1";
[thread1 start];
NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(act) object:nil];
thread2.name = @"thread2";
[thread2 start];
NSThread *thread3 = [[NSThread alloc]initWithTarget:self selector:@selector(act) object:nil];
thread3.name = @"thread3";
[thread3 start];
*/
// ---------------------------------------------
self.view.backgroundColor = [UIColor blackColor];
pointView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
pointView.backgroundColor = [UIColor whiteColor];
pointView.layer.cornerRadius = 50;
pointView.layer.masksToBounds = YES;
[self.view addSubview:pointView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tap:)];
[self.view addGestureRecognizer:tap];
UIButton *button = [UIButton buttonWithType:UIButtonTypeCustom];
button.frame = CGRectMake(10, 20, 100, 30);
[button setTitle:@"下载图片" forState:UIControlStateNormal];
[button addTarget:self action:@selector(loadData) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
}
/*
- (void)act
{
NSLog(@"%@",[NSThread currentThread]);
while (ticketNum >= 0) {
[condition lock];
if(ticketNum >= 0){
[NSThread sleepForTimeInterval:0.1];
count = 100 - ticketNum;
NSLog(@"当前票数是:%d,售出:%d,线程名:%@",ticketNum,count,[NSThread currentThread].name);
ticketNum--;
}
[condition unlock];
}
}
- (void)updata
{
sleep(10);
NSLog(@"子线程");
}
- (void)updata1
{
sleep(5);
NSLog(@"newThread子线程");
[self performSelector:@selector(yayaya) onThread:newThread withObject:nil waitUntilDone:YES];
}
- (void)yayaya
{
NSLog(@"执行");
}
*/
//普通
- (void)loadData
{
NSLog(@"...");
sleep(3);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://file.bmob.cn/M01/33/41/oYYBAFXcMhaARlGBAABOZfJ7P6Y062.png"]];
pointView.image = [UIImage imageWithData:data];
}
/*
//多线程
- (void)loadData
{
NSLog(@"...");
[NSThread detachNewThreadSelector:@selector(commentData) toTarget:self withObject:nil];
}
- (void)commentData
{
sleep(3);
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://file.bmob.cn/M01/33/41/oYYBAFXcMhaARlGBAABOZfJ7P6Y062.png"]];
pointView.image = [UIImage imageWithData:data];
}
*/
- (void)tap:(UITapGestureRecognizer *)sender
{
pointView.center = [sender locationInView:self.view];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end