iOS多线程的基本使用
一、NSThread:
程序就是一段代码,是静态的概念
进程是运行起来的程序,是动态的概念,进程需要占内存空间
线程是进程的基本单位,一个进程至少有一个线程,iOS程序默认有一个主线程,用来显示和操作UI,主线程由系统自动创建,有系统管理。如果主线程不能满足我们的需求,可以手动创建线程,手动创建的线程需要我们自己管理。
1.例:让一个线程延迟10秒运行
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//按钮一
UIButton *btn1 = [MyUtilcreateBtnFrame:CGRectMake(100,100, 80,40) title:@"按钮一"bgImageName:niltarget:selfaction:@selector(clickBtnOne:)];
[self.viewaddSubview:btn1];
//按钮二
UIButton *btn2 = [MyUtilcreateBtnFrame:CGRectMake(100,200, 80,40) title:@"按钮二"bgImageName:niltarget:selfaction:@selector(clickBtnTwo:)];
[self.viewaddSubview:btn2];
}
- (void)clickBtnOne:(id)sender
{
//模拟耗时较长的操作
//例如实际中的网络请求或者数据库的操作
//让线程睡眠十秒
[NSThreadsleepForTimeInterval:10];
//如果不使用多线程,会有界面假死的现象
//用户体验不好
//所有在这种情况下我们需要使用多线程
}
- (void)clickBtnTwo:(id)sender
{
NSLog(@"%s",__func__);
}
2.线程的优先级:
//用线程的这个属性来修改线程的优先级,属性值越大,执行的次数越多
t1.threadPriority =0;
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//线程一
NSThread *t1 = [[NSThreadalloc] initWithTarget:selfselector:@selector(threadOne)object:nil];
//修改优先级
//优先级的值在0-1之间,优先级越高,执行的次数相对来说会越多
t1.threadPriority =0;
[t1 start];
//线程二
NSThread *t2 = [[NSThreadalloc] initWithTarget:selfselector:@selector(threadTwo)object:nil];
//修改优先级,线和二大于线程一,线程二先执行完成
t2.threadPriority =1;
[t2 start];
}
- (void)threadOne
{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
}
- (void)threadTwo
{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
}
3. 线程锁:
第一种方法用: @synchronized加线程锁
-(void)withDraw:(float)money
{
//多个线程修改同一块资源的时候,会出现问题
//我们需要用线程锁的方式解决
@synchronized(self){
if (_money >= money) {
//模拟取钱的时间
[NSThreadsleepForTimeInterval:1];
_money -= money;
NSLog(@"%@取了%f元",[NSThreadcurrentThread].name,money);
}else{
NSLog(@"余额不足");
}
}
}
@end
第二种方法:
用NSLock 来实现加锁和解锁
@implementation MyAccount
{
//线程锁
NSLock *_myLock;
}
-(instancetype)init
{
if (self = [superinit]) {
_myLock = [[NSLockalloc] init];
}
returnself;
}
-(void)withDraw:(float)money
{
//多个线程修改同一块资源的时候,会出现问题
//我们需要用线程锁的方式解决
//加锁
[_myLocklock];
if (_money >= money) {
//模拟取钱的时间
[NSThreadsleepForTimeInterval:1];
_money -= money;
NSLog(@"%@取了%f元",[NSThreadcurrentThread].name,money);
}else{
NSLog(@"余额不足");
}
//解锁
[_myLockunlock];
}
@end
二:NSOpreation:
1.用NSOpreation实现在线下载图片
#import "ViewController.h"
#import "ImageOperation.h"
@interfaceViewController ()
{
NSOperationQueue *_queue;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//创建图片视图
UIImageView *myImageView = [[UIImageViewalloc] initWithFrame:CGRectMake(40,100, 300,300)];
[self.viewaddSubview:myImageView];
//使用NSOperatio自定制类型实现多线程
//1.创建一个队列
_queue = [[NSOperationQueuealloc] init];
//队列里面同时执行的线程最大数量
//例如往队列里面加了20个线程,只会执行10个,其他的线程要等这10个中的某个执行完成之后,才能执行
_queue.maxConcurrentOperationCount =10;
//2.创建ImageOperation对象
ImageOperation *op = [[ImageOperationalloc] init];
//设置下载链接
op.urlString=@"http://g.hiphotos.baidu.com/image/pic/item/4034970a304e251fb3145e6ca586c9177e3e5346.jpg";
//设置显示的视图
op.imgView = myImageView;
//添加到队列
[_queueaddOperation:op];
//ASIHttpRequest: NSOperation
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
#import "ImageOperation.h"
@implementation ImageOperation
//使用NSOperation自定制对象创建线程时的执行体
-(void)main
{
//下载图片
NSURL *url = [NSURLURLWithString:self.urlString];
NSData *data = [NSDatadataWithContentsOfURL:url];
//回到主线程修改UI
[selfperformSelectorOnMainThread:@selector(refreshUI:)withObject:data waitUntilDone:YES];
}
- (void)refreshUI:(NSData *)data
{
self.imgView.image = [UIImageimageWithData:data];
}
@end
2.使用NSOperation创建多线程:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//NSOperation实现多线程
//1.创建队列
_queue = [[NSOperationQueuealloc] init];
//2.创建NSInvocationOperation对象
/*
第一个参数:线程执行体方法所属的对象
第二个参数:线程执行体方法
第三个参数:线程执行体方法传递的实参
*/
NSInvocationOperation *op1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(threadOne)object:nil];
//线程结束之后执行的代码块
[op1 setCompletionBlock:^{
NSLog(@"线程一结束");
}];
//3.开启线程
[_queueaddOperation:op1];
//第二种实现线程的方式
NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{
//线程的执行体
for (int i=0; i<100; i++) {
NSLog(@"执行线程二:%d",i);
}
}];
//线程执行结束后调用的代码块
[op2 setCompletionBlock:^{
NSLog(@"线程二结束");
}];
//添加到队列里面
[_queueaddOperation:op2];
}
//线程执行体方法
- (void)threadOne
{
for (int i=0; i<100; i++) {
NSLog(@"执行了线程一:%d", i);
}
}
三:GCD:
1.用GCD实现多线程:
#import "ViewController.h"
@interfaceViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//1.同一块代码执行多次
//[self testApply];
//2.代码只执行一次
// [self testOnce];
// [self testOnce];
// [self testOnce];
// [self testOnce];
//3.在一段时间之后执行代码块
//[self testAfter];
//4.线程组(group)
//[self testGroup];
//5.在某几个线程都执行完成之后,并在另外几个线程都执行完成之前,需要执行一些代码
[selftestBarrier];
}
//5.在某几个线程都执行完成之后,并在另外几个线程都执行完成之前,需要执行一些代码
- (void)testBarrier
{
//队列不能是系统的全局队列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
//线程一
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
});
//线程二
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
});
//在线程一和线程二都执行完成之后,并且在线程三执行之前,调用一段代码块
dispatch_barrier_async(concurrentQueue, ^{
NSLog(@"barrier");
});
//线程三
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程三:%d", i);
}
});
}
//4.多个线程都执行之后去执行一些代码
- (void)testGroup
{
//线程组
dispatch_group_t group =dispatch_group_create();
/*
第一个参数:线程组
第二个参数:线程所在的队列
第三个参数:线程的执行体
*/
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
for (int i=0; i<100; i++) {
NSLog(@"执行了线程一:%d", i);
}
});
dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
for (int i=0; i<100; i++) {
NSLog(@"执行了线程二:%d", i);
}
});
//在该组的所有线程都执行结束时做执行某段代码
dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
NSLog(@"所有线程都执行完成");
});
}
//3.在一段时间之后执行代码块
- (void)testAfter
{
NSLog(@"执行之前");
//DISPATCH_TIME_NOW:表示当前的时间
//当前时间的十秒之后
dispatch_time_t myTime =dispatch_time(DISPATCH_TIME_NOW,NSEC_PER_SEC*10);
//队列
//创建一个并行的队列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
/*
第一个参数:代码块执行的时间
第二个参数:代码块的线程所在的队列
第三个参数:执行的代码块
*/
dispatch_after(myTime, concurrentQueue, ^{
NSLog(@"执行了代码块");
});
}
//2.代码只执行一次
//通常用来实现单例
- (void)testOnce
{
staticdispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"执行了一次");
});
}
//1.同一块代码执行多次
- (void)testApply
{
/*
第一个参数:代码块执行多少次
第二个参数:线程所在的队列
第三个参数:线程的执行体
*/
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//参数表示当前是第几次执行
dispatch_apply(10, globalQueue, ^(size_t time) {
//线程的执行体
NSLog(@"执行到了第%ld次", time);
});
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
2.GCD实现多线程2:
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//GCD实现多线程
//一、GCD的队列
//1.主线程所在的串行队列
//系统自动创建了这个队列,我们只要获取后使用
dispatch_queue_t mainQueue =dispatch_get_main_queue();
//2.系统的全局并行队列
//系统自动创建了这个队列,我们只能获取后使用
/*
第一个参数:队列的优先级
第二个参数:APPLE公司保留的参数
*/
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//3.自己创建的队列
//1)串行队列
/*
第一个参数:队列的标识符
第二个参数:用来区分是串行队列还是并行队列
DISPATCH_QUEUE_SERIAL:串行队列
DISPATCH_QUEUE_CONCURRENT:并行队列
*/
dispatch_queue_t serialQueue =dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);
//2)并行队列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
//二、GCD创建线程
//1、异步将线程的执行体代码放到队列执行
/*
第一个参数:队列
第二个参数:线程的执行体代码
*/
dispatch_queue_t queueOne =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queueOne, ^{
for (int i=0; i<100; i++) {
NSLog(@"执行了线程一:%d", i);
}
});
//2、同步将线程的执行体放到队列执行
dispatch_sync(queueOne, ^{
for (int i=0; i<100; i++) {
NSLog(@"执行了线程二:%d", i);
}
});
}
- (void)didReceiveMemoryWarning {
[superdidReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
3.GCD的串行和并行队列:
#import "ViewController.h"
@interfaceViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//1.以同步的方式在串行队列创建两个线程
//[self testSyncWithSerialQueue];
//2.以同步的方式在并行队列创建两个线程
//[self testSyncWithConcurrentQueue];
//3.以异步的方式在串行队列创建两个线程
//[self testAsyncWithSerialQueue];
//4.以异步的方式在并行队列创建两个线程
[selftestAsyncWithConcurrentQueue];
}
//4.以异步的方式在并行队列创建两个线程
//前面的线程和后面的线程同时执行
- (void)testAsyncWithConcurrentQueue
{
//创建并行队列
dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);
//线程一
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
});
//线程二
dispatch_async(concurrentQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
});
}
//3.以异步的方式在串行队列创建两个线程
//前面的线程执行完成,后面的线程才开始执行
- (void)testAsyncWithSerialQueue
{
//串行队列
dispatch_queue_t serialQueue =dispatch_queue_create("myQueue",DISPATCH_QUEUE_SERIAL);
//线程一
dispatch_async(serialQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
});
//线程二
dispatch_async(serialQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
});
}
//2.以同步的方式在并行队列创建两个线程
//前面的线程执行结束,才开始执行后面的线程
- (void)testSyncWithConcurrentQueue
{
//获取全局并行队列
dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
//线程一
dispatch_sync(globalQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
});
//线程二
dispatch_sync(globalQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
});
}
//1.以同步的方式在串行队列创建两个线程
//前面的线程执行完成之后,才开始执行后面的线程
- (void)testSyncWithSerialQueue
{
//创建一个串行队列
dispatch_queue_t serialQueue =dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);
//线程一
dispatch_sync(serialQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程一:%d", i);
}
});
//线程二
dispatch_sync(serialQueue, ^{
for (int i=0; i<100; i++) {
NSLog(@"线程二:%d", i);
}
});
}