多线程

这篇博客详细介绍了iOS开发中的多线程技术,包括NSThread的创建和启动方法,GCD的使用,以及NSOperation和NSOperationQueue的常见操作。通过实例展示了如何在不同线程中执行任务,强调了线程同步的重要性,并提供了从其他线程回到主线程的几种方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

概念:

//什么是进程?

//1.进程是指在系统中正在运行的一个应用程序
//2.每个进程之间是独立的,每个进程均运行在其专用且受保护的内存空间内


//什么是线程?
//1.1个进程想要执行任务,必须得有线程(每个进程至少要有1条线程)
//2.线程是进程的基本执行单元,一个进程(程序)的所有任务都在线程中执行


//什么是多线程
//1个进程中可以开启多条线程,每条线程可以并行(同时)执行不同任务


//多线程原理
//同一时间,CPU只能处理一条线程,只有一条线程在工作(执行)。多线程并发(同时)执行,其实是CPU快速地在多条线程之间调度(切换)如果CPU调度线程的时间足够快,就造成了多线程并发执行的假象


//如果线程非常非常多,会发生么情况?
//CPU会在n多线程之间调度,CPU会累死,消耗大量的CPU资源


//多线程的优点
//1.能适当提高程序的执行效率
//2.能适当提高资源利用率(CPU,内存利用率)


//多线程的缺点
//1.开启大量的线程,占用大量的内存空间,降低程序的性能
//2.线程越多,CPU在调度线程上的开销就越大
//3.程序设计更加复杂,比如线程之间的通信,线程的资源共享


//什么是主线程
//一个IOS程序运行后,默认会开启一条线程,成为“主线程”或“UI线程”


//主线程的主要作用
//1.显示\刷新UI界面
//2.处理UI事件(比如点击事件,滑动事件,拖拽事件等)


//主线程的使用注意
//1.别将比较耗时的操作放到主线程中
//2.耗时操作会卡住主线程,严重影响UI的流畅度,给用户一种“卡”的坏体验


//IOS中多线程的实现方案
//1.NSThread
//使用起来更加面向对象
//简单易用,可直接操作线程对象
//OC语言
//程序猿管理线程的生命周期
//偶尔使用 使用里面的个别方法
//
//2.GCD
//意在代替NSThread等线程技术
//充分利用设备的多核
//C语言
//自动管理线程的生命周期
//经常使用
//
//3.NSOperation
//基于GCD(底层是GCD)
//比GCD多了一些简单实用的功能
//实用更加面向对象
//自动管理线程的生命周期

//经常使用


1.NSThread

#import "ViewController.h"


@interface ViewController ()


@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

    UISwitch *switchButton = [[UISwitch alloc] initWithFrame:CGRectMake(0, 200, 70, 30)];

    [self.view addSubview:switchButton];

    

    UITextView *textView = [[UITextView alloc] initWithFrame:CGRectMake(0, 250, 320, 100)];

    textView.editable = NO;

    [textView setFont:[UIFont systemFontOfSize:30]];

    [textView setText:@"nnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsafnnasdjfasjdfsjdfsdafdsfdsaf"];

    [self.view addSubview:textView];

}


- (void)loadData:(NSString *)str

{

    //获取当前线程

    NSLog(@"下载东西 ----- %@",[NSThread currentThread]);

    //获取主线程

    NSLog(@"拿到主线程 ---- %@",[NSThread mainThread]);

    NSLog(@"str --- %@",str);

    

//    //睡眠3

//    [NSThread sleepForTimeInterval:3];

    //睡眠到一个NSDate为止

    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3];

    [NSThread sleepUntilDate:date];

    

    for (int i=0; i<10000; i++) {

        NSLog(@"------------ %d",i);

    }

}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    [self createThread1];

}


//穿件线程方法3 隐式创建线程

- (void)createThread3

{

    //不会创建线程

//    [self performSelector:@selector(loadData:) withObject:@"performSelector"];

    [self performSelectorInBackground:@selector(loadData:) withObject:@"performSelectorInBackground"];

}


//创建线程方法2 创建线程自动启动

- (void)createThread2

{

    [NSThread detachNewThreadSelector:@selector(loadData:) toTarget:self withObject:@"detachNewThreadSelector"];

}


//创建线程方法1 创建线程然后启动线程

- (void)createThread1

{

    //创建线程

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData:) object:@"NSThread"];

    thread.name = @"下载线程";

    //启动线程

    [thread start];

}


@end

2.GCD

@interface ViewController ()

{

    UIImageView *_imageView;

}

@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

    _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];

    [_imageView setBackgroundColor:[UIColor blueColor]];

    [self.view addSubview:_imageView];

}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    

    //创建队列组

    dispatch_group_t group = dispatch_group_create();

    //获得全局并发队列

    dispatch_queue_t globalConCurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    

    __block UIImage *image1=nil;

    __block UIImage *image2=nil;

    //下载图片1

    dispatch_group_async(group, globalConCurrentQueue, ^{

        NSLog(@"_____%@",[NSThread currentThread]);

        NSURL *url1 = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/image/pic/item/8718367adab44aed3eb376e9b11c8701a18bfb3a.jpg"];

        NSData *data1 = [NSData dataWithContentsOfURL:url1];

        NSLog(@"data1 %@",data1);

        image1 = [UIImage imageWithData:data1];

    });

    //下载图片2

    dispatch_group_async(group, globalConCurrentQueue,^{

        NSLog(@"_____%@",[NSThread currentThread]);

        NSURL *url2 = [NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"];

        NSData *data2 = [NSData dataWithContentsOfURL:url2];

        NSLog(@"data2 %@", data2);

        image2 = [UIImage imageWithData:data2];

    });


    //3.合并图片

    dispatch_group_notify(group, globalConCurrentQueue, ^{

        

        //开启一个位图上下文

        UIGraphicsBeginImageContext(image1.size);

        

        //绘制图片1

        [image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];

        //绘制图片2

        [image2 drawInRect:CGRectMake(image1.size.width-image2.size.width*0.4, image1.size.height-image2.size.height*0.4, image2.size.width*0.4, image2.size.height*0.4)];

        

        //得到上下文中的图片

        UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();

        

        //结束上下文

        UIGraphicsEndImageContext();

        

        //回到主线程显示图片

        dispatch_async(dispatch_get_main_queue(), ^{

            [_imageView setImage:fullImage];

            [_imageView setFrame:CGRectMake(0, 0, image1.size.width*0.4, image1.size.height*0.4)];

        });

        

    });

    

}


- (void)test1

{

    //获得全局并发队列

    dispatch_queue_t globalConCurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    dispatch_async(globalConCurrentQueue, ^{

        //1.下载图片1

        NSURL *url1 = [NSURL URLWithString:@"http://a.hiphotos.baidu.com/image/pic/item/8718367adab44aed3eb376e9b11c8701a18bfb3a.jpg"];

        NSData *data1 = [NSData dataWithContentsOfURL:url1];

        UIImage *image1 = [UIImage imageWithData:data1];

        //2.下载图片2

        NSURL *url2 = [NSURL URLWithString:@"https://ss0.bdstatic.com/5aV1bjqh_Q23odCf/static/superplus/img/logo_white_ee663702.png"];

        NSData *data2 = [NSData dataWithContentsOfURL:url2];

        UIImage *image2 = [UIImage imageWithData:data2];

        

        NSLog(@"image1 %@ image2 %@",image1,image2);

        

        //3.合并图片

        //开启一个位图上下文

        UIGraphicsBeginImageContext(image1.size);

        

        //绘制图片1

        [image1 drawInRect:CGRectMake(0, 0, image1.size.width, image1.size.height)];

        //绘制图片2

        [image2 drawInRect:CGRectMake(image1.size.width-image2.size.width*0.4, image1.size.height-image2.size.height*0.4, image2.size.width*0.4, image2.size.height*0.4)];

        

        //得到上下文中的图片

        UIImage *fullImage = UIGraphicsGetImageFromCurrentImageContext();

        

        //结束上下文

        UIGraphicsEndImageContext();

        

        //回到主线程显示图片

        dispatch_async(dispatch_get_main_queue(), ^{

            [_imageView setImage:fullImage];

            [_imageView setFrame:CGRectMake(0, 0, image1.size.width*0.4, image1.size.height*0.4)];

        });

        

    });

}



3.NSOperation

#import "ViewController.h"


@interface ViewController ()<UITableViewDelegate>

{

    UIImageView *_imageView;

}

@end


@implementation ViewController


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 320, 320)];

    [_imageView setBackgroundColor:[UIColor blueColor]];

    [self.view addSubview:_imageView];

    

    [self baseUse2];

}


- (void)baseUse3

{

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];


    [queue addOperationWithBlock:^{

        //1.异步下载图片

        NSString *urlString = @"http://f.hiphotos.baidu.com/image/pic/item/7c1ed21b0ef41bd540153bf853da81cb39db3d7c.jpg";

        NSURL *imageUrl = [NSURL URLWithString:urlString];

        NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];

        UIImage *image = [UIImage imageWithData:imageData];

        

//        [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>]

//        dispatch_async(dispatch_get_main_queue(), <#^(void)block#>)

        

        NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

        [mainQueue addOperationWithBlock:^{

            [_imageView setImage:image];

        }];

    }];

    

}


- (void)baseUse2

{

    //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]);

    }];

    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下载图片3 ----%@",[NSThread currentThread]);

    }];

    NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下载图片4 ----%@",[NSThread currentThread]);

    }];

    

    //设置依赖

    [operation2 addDependency:operation1];

    [operation3 addDependency:operation2];

    [operation4 addDependency:operation3];

    

    [queue addOperation:operation1];

    [queue addOperation:operation2];

    [queue addOperation:operation3];

    [queue addOperation:operation4];

    [queue addOperationWithBlock:^{

        NSLog(@"下载图片5 ----%@",[NSThread currentThread]);

    }];


}


- (void)baseUse1

{

    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下载图片1--------%@",[NSThread currentThread]);

    }];

    

    [blockOperation addExecutionBlock:^{

        NSLog(@"下载图片2--------%@",[NSThread currentThread]);

    }];

    

    [blockOperation addExecutionBlock:^{

        NSLog(@"下载图片3--------%@",[NSThread currentThread]);

    }];

    

    [blockOperation setCompletionBlock:^{

        NSLog(@"操作结束");

    }];

    

    [blockOperation start];

}


- (void)didReceiveMemoryWarning {

    [super didReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

    //    [queue cancelAllOperations];//取消队列中的所有任务(不可恢复)

}


- (void)scrollViewWillBeginDragging:(UIScrollView *)scrollView

{

    //    [queue setSuspended:YES];//暂停队列中的所有任务

}


- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate

{

    //    [queue setSuspended:NO];//恢复队列中的所有任务

}


@end



多线程总结:

一,线程注意点

1.不要同时开太多线程,(1-3个线程即可,不要超过5个)

2.线程概念

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

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

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



二,NSThread

1.创建和启动线程的3种方法


1》先创建 后启动

//创建线程

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData:) object:nil];

//启动线程

[thread start];


2》创建完自动启动

[NSThread detachNewThreadSelector:@selector(loadData:) toTarget:self withObject:nil];


3》隐式创建自动启动

[self performSelectorInBackground:@selector(loadData:) withObject:nil];



2.常见方法


1》获得当前线程

+ (NSThread *)currentThread;


2》获得主线程

+ (NSThread *)mainThread;


3》睡眠(暂停)线程

+ (void)sleepUntilDate:(NSDate *)date;

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;


4》设置线程名字

- (void)setName:(NSString *)n;

- (NSString *)name;


三,线程同步

1.实质:为了防止多个线程抢夺同一个资源造成的数据安全问题---

2.实现:给代码加一个互斥锁(同步锁)

@synchronized(self){

    //被锁住的代码块

}


四,GCD

1.任务和队列


1》任务:需要执行什么操作 block来封装任务

同步执行 不具备开启线程的能力

dispatch_sync

异步执行 具备开启新线程的能力

dispatch_async


2》队列:存放任务


全局并发队列:可以让任务并发执行

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);


自己创建的串行队列:让任务一个接着一个执行

dispatch_queue_t queue = dispatch_queue_create("SerialQueue", DISPATCH_QUEUE_SERIAL);


主队列:让任务在主线程中执行

dispatch_queue_t queue = dispatch_get_main_queue();


2.常见任务和队列组合

1dispatch_async + 全局并发队列

2dispatch_async + 自定义串行队列

3dispatch_async + 主队列


3.延迟执行

1- (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;

2dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

//    --------dosomething-------

});


五,NSOperationNSOperationQueue

1.队列的类型

1》主队列

[NSOperationQueue mainQueue];

添加到主队列中的操作,都会放到主线程中执行


2》非主队列

[[NSOperationQueue alloc] init];

添加到非主队列中操作,都会放到子线程中执行


2.队列添加任务

- (void)addOperation:(NSOperation*)op;

- (void)addOperationWithBlock:(void (^)(void))block;


3.常见用法

1》最大并发数

maxConcurrentOperationCount

2》设置依赖关系解除依赖关系

- (void)addDependency:(NSOperation *)op;

- (void)removeDependency:(NSOperation *)op;


4.队列其他操作

1》取消所有操作

[queue cancelAllOperations];//取消队列中的所有任务(不可恢复)

2》暂停所有操作

[queue setSuspended:YES];//暂停队列中的所有任务

3》恢复所有操作

[queue setSuspended:NO];//恢复队列中的所有任务


六,从其他线程回到主线程的方式

1perform

[self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>]


2dispatch

dispatch_async(dispatch_get_main_q<#^(void)block#>ueue(), )


3NSOperationQueue

NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];

[mainQueue addOperationWithBlock:^{

    ---dosomething----

}];










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值