1.多线程的基本概念
每一个程序都有一个主线程,程序启动时创建(调用main来启动)
主线程的生命周期是和应用程序绑定的,程序结束时,主线程也就停止
多线程技术表示,一个应用程序有多个线程,使用多线程能提供cup的使用率,防止主线程阻塞
任何有可能堵塞主线程的任务不要在主线程执行(访问网络)
注意:
线程使用不是无节制的
只有主线程有直接修改UI的能力(子线程与主线程通信)
2.多线程技术
3.线程的创建与启动
01.NSThread:
- (void)viewDidLoad {
[super viewDidLoad];
// 开启了一个子线程,主线程继续执行,子线程也继续执行
// 1、[NSThread detachNewThreadSelector:@selector(test1) toTarget:self withObject:nil];
// 2、alloc 创建线程需要手动开启
/*
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(test1) object:nil];
// 手动开启线程
[thread start];
[self test2];
*/
// 3、设置图片
imgView = [[UIImageView alloc] initWithFrame:CGRectMake(60, 100, 200, 200)];
imgView.backgroundColor = [UIColor redColor];
[self.view addSubview:imgView];
NSLog(@"current Thread : %@", [NSThread currentThread]);
}
- (void)refreshUI:(UIImage *)image
{
imgView.image = image;
}
#pragma mark - 设置图片
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
//[NSThread detachNewThreadSelector:@selector(subThread:) toTarget:self withObject:@(2)];
// 开启后台线程(子线程)
[self performSelectorInBackground:@selector(subThread:) withObject:nil];
}
- (void)subThread:(NSNumber *)number
{
// ARC
// 因为在子线程创建的自动释放的对象,是不能够入主线程的自动释放中的
@autoreleasepool {
NSLog(@"current Thread : %@", [NSThread currentThread]);
// 耗时操作
NSURL *url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/image/w%3D2048/sign=110ed40be9f81a4c2632ebc9e3126159/b3b7d0a20cf431add6d225464936acaf2edd9848.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
// 刷新UI 错误了!不能在子线程中刷新UI的事情,很有可能会崩溃
//imgView.image = image;
// 只能在主线程做刷新UI,涉及到主线程和子线程通信(NSObject中方法)
/**
* 从子线程回到主线程
* (1)回到主线程的方法
* (2)传递的参数可以为空
* (3)YES,必须等待主线程refreshUI:
NO,不需要等待
*/
[self performSelectorOnMainThread:@selector(refreshUI:) withObject:image waitUntilDone:YES];
// 假设子线程还有若干事情
// YES,必须走完refreshUI:
// NO,主线程继续执行,子线程也接着执行
}
}
#pragma mark - 开启了线程了,打印交替进行了(2条执行路径)
- (void)test1
{
for (int i = 0; i < 1000; i++) {
// 性能开销比较大
NSLog(@"task 1: %d", i);
}
}
- (void)test2
{
for (int i = 0; i < 100; i++) {
// 性能开销比较大
NSLog(@"task 2: %d", i);
}
}
#pragma mark - NSLog 性能开销比较大
- (IBAction)task1:(UIButton *)sender {
for (int i = 0; i < 10000; i++) {
// 性能开销比较大
//NSLog(@"task 1: %d", i);
}
//NSLog(@"task 1");
}
- (IBAction)task2:(UIButton *)sender {
for (int i = 0; i < 100000; i++) {
}
//NSLog(@"task 2");
}
NSThread的常用方法:
//获取当前线程对象
+ (NSThread *)currentThread;
//使当前线程睡眠指定的时间,单位为秒
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//退出当前线程
+ (void)exit;
//判断当前线程是否为主线程
+ (BOOL)isMainThread
//启动该线程
- (void)start
// 如果我们DEBUG模式【调试】(RELEASE模式【发布】)
/**
* 源代码
* 编译(目标代码).o
/ Debug 系统库文件(冗余,多)
* 链接(多个文件,用户定义文件,系统库文件)
* \ Release 系统库文件(少)
*/
#ifdef DEBUG
#define MYLog(...) NSLog(__VA_ARGS__)
#else
#define MYLog(...)
#endif
02.NSOperation
@interface ViewController ()
{
NSOperationQueue *queue;
}
@end
@implementation ViewController
/**
* 阻塞主线程 - 耗时的操作
*/
- (void)viewDidLoad {
[super viewDidLoad];
// 同步:先做A【耗时操作、界面卡顿】,再去做B
// 异步:同时进行A、B和操作
// 1 同步操作
/*
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(op1)
object:nil];
// 开启了操作,调用指定的方法
[op1 start];
*/
// NSOperation 抽象类,不实例化
/**
* (1) NSInvocationOperation
* (2) NSBlockOperation
*/
// 2 异步操作
NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op1) object:nil];
// 设置优先级
[op1 setQueuePriority:NSOperationQueuePriorityVeryLow];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op2) object:nil];
[op2 setQueuePriority:NSOperationQueuePriorityVeryHigh];
// 当子线程完成时
[op2 setCompletionBlock:^{
//
NSLog(@"YES : %@", [NSThread currentThread]);
}];
NSInvocationOperation *op3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op3) object:nil];
[op3 setQueuePriority:NSOperationQueuePriorityLow];
NSInvocationOperation *op4 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op4) object:nil];
[op4 setQueuePriority:NSOperationQueuePriorityNormal];
NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
//NSLog(@"op2 : %@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
NSLog(@"block op5 is :%d", i);
}
}];
[op5 setQueuePriority:NSOperationQueuePriorityHigh];
// 一旦将操作对象放入“操作队列”中,这个操作就变了异步操作(开启一个线程)
// 此外,我们不需要将“操作”对象手动开启,当这个操作加入到“队列”中,事情开始了
queue = [[NSOperationQueue alloc] init];
// 设置队列的并发数
[queue setMaxConcurrentOperationCount:1];
//[queue addOperation:op1];
//[queue addOperation:op2];
//[queue addOperation:op3];
//[queue addOperation:op4];
//[queue addOperation:op5];
NSArray *ops = @[op1, op2, op3, op4, op5];
// YES 阻塞当前线程(主线程),必须等待所有“操作队列”结束之后
// NO 不会阻塞主线程
[queue addOperations:ops waitUntilFinished:NO];
// 3 设置依赖关系
/*
NSBlockOperation *op7 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello op7");
}];
NSBlockOperation *op8 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello op8");
// 根据栏目ID,请求具体内容
}];
NSBlockOperation *op9 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"hello op9");
// 先请求栏目数据 NSArray【model】
}];
// 设置依赖关系,切记不要“循环依赖” 得出op9 op8 op7
[op7 addDependency:op8];
[op8 addDependency:op9];
queue = [[NSOperationQueue alloc] init];
[queue addOperations:@[op7, op8, op9] waitUntilFinished:NO];
*/
}
- (void)op1
{
//NSLog(@"op1 : %@", [NSThread currentThread]);
for (int i = 0; i < 10; i++) {
NSLog(@"op1 is : %d", i);
}
//子线程与主线程之间通信
//[self performSelectorOnMainThread:@selector(test) withObject:nil waitUntilDone:YES];
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"hello %@", [NSThread currentThread]);
}];
}
- (void)op2
{
for (int i = 0; i < 10; i++) {
NSLog(@"op2 is : %d", i);
}
}
- (void)op3
{
for (int i = 0; i < 10; i++) {
NSLog(@"op3 is : %d", i);
}
}
- (void)op4
{
for (int i = 0; i < 10; i++) {
NSLog(@"op4 is : %d", i);
}
}
同步是无法取消的。
还学了线程锁:
// synchronized 锁的作用
/*
@synchronized(self) {
if (_allTickts > 0) {
// 线程睡眠(测试)
[NSThread sleepForTimeInterval:2];
_allTickts--;
NSLog(@"_allTickts : %d", _allTickts);
}else {
NSLog(@"票已经卖了");
}
}*/
// NSLock
/*
[_lock lock];
03.GCD
- (void)viewDidLoad {
[super viewDidLoad];
//[self gcd1];
//[self gcd2];
[self gcd3];
}
- (void)gcd3
{
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("com.wxhl.c", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
NSLog(@"t 1: %@", [NSThread currentThread]);
for (int i = 0; i < 20; i++) {
NSLog(@"t 1 : %d", i);
}
});
dispatch_group_async(group, queue, ^{
NSLog(@"t 2: %@", [NSThread currentThread]);
for (int i = 0; i < 20; i++) {
NSLog(@"t 2 : %d", i);
}
});
dispatch_group_notify(group, queue, ^{
NSLog(@"finish : %@", [NSThread currentThread]);
});
dispatch_group_t group1 = dispatch_group_create();
dispatch_queue_t queue1 = dispatch_queue_create("com.wxhl.c", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group1, queue1, ^{
NSLog(@"g 1: %@", [NSThread currentThread]);
for (int i = 0; i < 100; i++) {
NSLog(@"g 1 : %d", i);
}
});
dispatch_group_notify(group1, queue1, ^{
NSLog(@"finish");
});
}
- (void)gcd2
{
// 死锁问题
// 串行队列
dispatch_queue_t queue = dispatch_get_main_queue();
// 主队列
dispatch_sync(queue, ^{
NSLog(@"sync1 : %@", [NSThread currentThread]);
});
}
- (void)gcd1
{
/**
* (1) 队列的名字 "com.wxhl.q"
* (2) 队列的属性
a. DISPATCH_QUEUE_CONCURRENT (并发队列(global_queue),并发线程队列)
b. DISPATCH_QUEUE_SERIAL (串行队列 只会创建一个子线程,顺序执行(依赖))
c. dispatch_get_main_queue 主队列
* (3) 是否开辟子线程,看对队列,和异步和同步无关,如果是主队列,在主线程中,其他队列都是创建了子线程
*/
dispatch_queue_t queue = dispatch_queue_create("com.wxhl.q", DISPATCH_QUEUE_CONCURRENT);
/**
* 队列的优先级
*/
//dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
NSLog(@"t 1 : %@", [NSThread currentThread]);
for (int i = 0; i < 20; i++) {
NSLog(@"t 1 : %d", i);
}
/*
// 同步
dispatch_sync(dispatch_get_main_queue(), ^{
NSLog(@"%@", [NSThread currentThread]);
});*/
// 异步(请参考 waitUntilDone:YES理解)
dispatch_async(dispatch_get_main_queue(), ^{
//NSLog(@"%@", [NSThread currentThread]);
});
});
dispatch_async(queue, ^{
NSLog(@"t 2 : %@", [NSThread currentThread]);
for (int i = 0; i < 20; i++) {
NSLog(@"t 2 : %d", i);
}
});
dispatch_async(queue, ^{
NSLog(@"t 3 : %@", [NSThread currentThread]);
for (int i = 0; i < 20; i++) {
NSLog(@"t 3 : %d", i);
}
});
//[NSThread detachNewThreadSelector:@selector(test1) toTarget:self withObject:nil];
}
- (void)test1
{
// .....
[self performSelectorOnMainThread:@selector(refreshUI) withObject:nil waitUntilDone:YES];
// .....
}
- (void)refreshUI
{
}