iOS多线程总结

一 多线程之间的关系

二、
安全

二 NSThread

一旦线程中止死亡了,就不能再启动。因此线程NSThread不能为全局变量多线程

1>.建立和启动

1.第一种方法:直接建立,手动启动
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:@"www.baidu.com"];
    [thread start];

2.第二种方法:建立后当即启动    
    [NSThread detachNewThreadSelector:@selector(download) toTarget:self withObject:@"www.baidu.com"];
    
3.第三种方法:隐式建立
    //主线程
    [self performSelector:@selector(download:) withObject:@"www.baidu.com"];
    //子线程
    [self performSelectorInBackground:@selector(download:) withObject:@"www.baidu.com"];
    
object是selector方法传递的参数
-(void)download:(NSString *)url
{
    NSLog(@"download-- %@  %@",url,[NSThread currentThread]);
}

2>.睡眠的用法

延迟执行不要勇sleep,坏处:卡住主线程
1.第一种
    [NSThread sleepForTimeInterval:5.0];
2.第二种    
    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3.0];
    [NSThread sleepUntilDate:date];

3>.强制中止进程

+(void)exit

4>.其余用法

+(NSThread *)mainThread;
+(NSThread *)currentThread
-(BOOL)isMainThread;
+(BOOL)isMainThread;

5>.线程间通讯

在1个进程中,线程每每不是孤立存在的,多个线程之间须要常常进行通讯。体如今两个方面:一,1个线程的数据传递给另外一个线程。二,在1个线程中执行完特定任务后,转到另外一个线程继续执行任务
并发

-(void)download:(NSString *)url
{
    NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
    UIImage *image = [UIImage imageWithData:data];
    
    [self performSelectorOnMainThread:@selector(pic:) withObject:image waitUntilDone:YES];
}

-(void)pic:(UIImage *)image
{
    NSLog(@"pic:%@",image);
    self.imageView.image = image;
}

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(download:) withObject:@"http://g.hiphotos.baidu.com/image/h%3D200/sign=f23ec3ed1fd8bc3ed90801cab289a6c8/7a899e510fb30f24dc189ad4ce95d143ac4b0362.jpg"];
}


三 GCD

1>线程:同步与异步

同步:只能在当前线程中执行任务,不具有开启新线程的能力异步

异步:能够在新的线程中执行任务,具有开启新线程的能力async

2>任务:并发与串行

并发:可让多个任务并发(同时)执行,自动开启多线程。只有在异步下才有效atom

串行:让任务一个接一个地执行url

-(void)asyncGlobalQueue
{
    //得到全局的并发队列
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); //第一个参数是优先级
    //异步并行。自动建立多条线程
    dispatch_async(queue, ^{
        NSLog(@"将任务放到全局队列中执行 %@",  [NSThread currentThread]);
        dispatch_async(queue, ^{
            NSLog(@"异步并行1 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"异步并行2 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"异步并行3 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"异步并行4 %@",  [NSThread currentThread]);
        });
        dispatch_async(queue, ^{
            NSLog(@"异步并行5 %@",  [NSThread currentThread]);
        });
        
    });
}

-(void)asyncSerialQueue
{
    //异步串行,自动会建立线程,但只开1条
    dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL);

    dispatch_async(queue, ^{
        NSLog(@"异步串行1 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步串行2 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步串行3 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步串行4 %@",  [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"异步串行5 %@",  [NSThread currentThread]);
    });
}

-(void)syncGlobalQueue
{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //同步并行。不会建立线程,使用主线程
    dispatch_sync(queue, ^{
        NSLog(@"同步并行1 %@",  [NSThread currentThread]);
        NSLog(@"同步并行2 %@",  [NSThread currentThread]);
        NSLog(@"同步并行3 %@",  [NSThread currentThread]);
        NSLog(@"同步并行4 %@",  [NSThread currentThread]);
        NSLog(@"同步并行5 %@",  [NSThread currentThread]);
    });
}

-(void)syncSerialQueue
{
    dispatch_queue_t queue = dispatch_queue_create("cn.wx", NULL);
    //同步串行。不会建立线程,使用主线程
    dispatch_sync(queue, ^{
        NSLog(@"同步并行1 %@",  [NSThread currentThread]);
        NSLog(@"同步并行2 %@",  [NSThread currentThread]);
        NSLog(@"同步并行3 %@",  [NSThread currentThread]);
        NSLog(@"同步并行4 %@",  [NSThread currentThread]);
        NSLog(@"同步并行5 %@",  [NSThread currentThread]);
    });
}

3>.主队列

-(void)mainQueue
{
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    dispatch_async(queue, ^{
        NSLog(@"虽然是异步,可是是在主线程执行,因此不会开线程");
    });
//    dispatch_sync(queue, ^{
//        NSLog(@"不能在串行上使用主队列,不然会阻塞");
//    });
    
}

4>.线程间通讯

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        NSLog(@"子线程进行操做");
        
        dispatch_async(dispatch_get_main_queue(), ^{
            NSLog(@"回主线程加载图片");
        });
        
    });

5>.延时执行

不要使用sleep,会卡住主线程spa

第一种:
[self performSelector:@selector(down) withObject:@"abv" afterDelay:3];
第二种:
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"xx");//回到主线程
    });
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), queue, ^{
        NSLog(@"xx");//回到子线程
    });

6>.只执行一次

    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"xx");
    })


四 NSOperation

1>.简述

先将须要执行的操做封装到一个NSOperation对象,一个对象就至关于GCD的一个block线程

而后将NSOperation对象添加到NSOperationQueue中code

系统会自动将NSOperationQueue中的NSOperation取出来

将取出的NSOperation封装的操做放到一条线程中执行

2>.NSOperation的使用

NSOperation是个抽象类,不具有封装的能力,必须使用它的子类

1>NSInvocationOperation

    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil];
    /*
    [operation start]; 若是直接start,那么将会在当前线程(主线程)同步执行
    */
     //添加操做到队列中
    [queue addOperation:operation];

2>NSBlockOperation

第一种状况:同步
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载一 %@",[NSThread currentThread]);
    }];
    [operation start]; // 若是直接start,那么将会在当前线程(主线程)同步执行
    
第二种状况:异步
    NSBlockOperation *operation = [[NSBlockOperation alloc] init];
    //operation操做添加多个操做
    [operation addExecutionBlock:^{
        NSLog(@"下载一 %@",[NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"下载二 %@",[NSThread currentThread]);
    }];
    
    [operation addExecutionBlock:^{
        NSLog(@"下载三 %@",[NSThread currentThread]);
    }];
    
    [operation start];

ps:NSBlockOperation还能够直接建立使用对象
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载一 %@",[NSThread currentThread]);
    }];

3>自定义子类继承NSOperation

3.NSOperationQueue的使用

1>.基本使用

    //1.建立一个队列(非主队列)
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    //设置最大并发数
    queue.maxConcurrentOperationCount = 2;
    
    //2.建立操做
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载图片1 -- %@",[NSThread currentThread]);
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载图片2 -- %@",[NSThread currentThread]);
    }];
    NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(down) object:nil];
    
    //操做完后立刻执行另外一个操做
    [operation1 setCompletionBlock:^{
        NSLog(@"下载图片222");
    }];
    
    //操做依赖,注意不能相互依赖
    [operation2 addDependency:operation1];
    [operation3 addDependency:operation2];
    
    //3.添加操做到队列中(自动异步执行任务,并发)
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];

2>其余用法

    [queue cancelAllOperations]; //取消队列的全部操做。也能够直接调用NSOperation的cancel
    [queue setSuspended:YES]; //暂停和恢复队列。yes为暂停
    
经常使用场景:
-(void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    [queue cancelAllOperations];
}

-(void)scrollViewWillBeginDecelerating:(UIScrollView *)scrollView
{
    [queue setSuspended:YES];
}

-(void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate
{
    [queue setSuspended:NO];
}

3>.线程安全

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        //1.异步下载图片
        NSURL *url = [NSURL URLWithString:@"www.baidu.com"];
        NSData *data = [NSData dataWithContentsOfURL:url];
        UIImage *image = [UIImage imageWithData:data];
        
        //2.回到主线程设置图片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];


五 互斥锁

    self.obj = [[NSObject alloc] init];
    //锁任意对象,而且须要是惟一一把,因此须要创建个全局变量对象
    @synchronized(self.obj) {
        
    }

2.atomic:线程安全,须要消耗大量的资源。不建议须要


六 线程注意点

1.不要同时开太多线材(1~3条线材便可,不要超过5条)

2.线程概念

1>主线程:UI线程,显示、刷新UI界面,处理UI控件的事件

2>子线程:后台线程,异步线程

3.不要把耗时的操做放在主线程,要放在子线程中执行

相关文章
相关标签/搜索