iOS多线程几种不同方式简单使用

来源:互联网 发布:c语言数据结构源代码 编辑:程序博客网 时间:2024/06/02 04:27

1、首先说一下进程与线程

线程是指进程内的一个执行单元,也是进程内的可调度实体.
线程与进程的区别:
(1)地址空间:线程是进程内的一个执行单元;进程至少有一个线程;它们共享进程的地址空间;而进程有自己独立的地址空间;
(2)资源拥有:进程是资源分配和拥有的单位,同一个进程内的线程共享进程的资源
(3)线程是处理器调度的基本单位,但进程不是.
(4)二者均可并发执行.

进程和线程都是由操作系统所体会的程序运行的基本单元,系统利用该基本单元实现系统对应用的并发性。进程和线程的区别在于:

简而言之,一个程序至少有一个进程,一个进程至少有一个线程.
线程的划分尺度小于进程,使得多线程程序的并发性高。
另外,进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行效率。
线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口、顺序执行序列和程序的出口。但是线程不能够独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。但操作系统并没有将多个线程看做多个独立的应用,来实现进程的调度和管理以及资源分配。这就是进程和线程的重要区别。

进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.

2、iOS多线程几种不同方式的简单使用:

(1)、使用系统方法创建多线程:


@interface NSObject (NSThreadPerformAdditions)- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array;- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;// equivalent to the first method with kCFRunLoopCommonModes- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray<NSString *> *)array NS_AVAILABLE(10_5, 2_0);- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);// equivalent to the first method with kCFRunLoopCommonModes- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);@end

由上面代码可见这是NSObject类的分类,那么NSObject的所有子类都可以使用


下面直接看代码

#import "ViewController.h"@interface ViewController ()@end@implementation ViewController- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        [self systemThread];    }//直接调用UI中封装的方法,使用最简单-(void)systemThread{    //添加线程任务    [self performSelectorInBackground:@selector(task1) withObject:nil];    [self performSelectorInBackground:@selector(task2) withObject:nil];    [self performSelectorInBackground:@selector(task3) withObject:nil];}-(void)task1{    sleep(1);    NSLog(@"%s,%@",__func__,[NSDate date]);}-(void)task2{    sleep(2);    NSLog(@"%s,%@",__func__,[NSDate date]);}-(void)task3{    sleep(3);    NSLog(@"%s,%@",__func__,[NSDate date]);}- (void)didReceiveMemoryWarning {    [super didReceiveMemoryWarning];    // Dispose of any resources that can be recreated.}@end
输出:

2015-11-09 09:57:42.725 04-多线程总结[1061:22514] -[ViewController task1],2015-11-09 01:57:42 +00002015-11-09 09:57:43.675 04-多线程总结[1061:22515] -[ViewController task2],2015-11-09 01:57:43 +00002015-11-09 09:57:44.725 04-多线程总结[1061:22516] -[ViewController task3],2015-11-09 01:57:44 +0000
线程任务之间互不影响,除非发生资源竞争。更新UI时将任务添加到主线程performSelectorOnMainThread

(2)NSThread


@class NSArray<ObjectType>, NSMutableDictionary, NSDate, NSNumber, NSString;NS_ASSUME_NONNULL_BEGIN@interface NSThread : NSObject  {@private    id _private;    uint8_t _bytes[44];}//获取当前线程+ (NSThread *)currentThread;//开辟一个子线程,添加任务,并且立即执行线程+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;+ (BOOL)isMultiThreaded;@property (readonly, retain) NSMutableDictionary *threadDictionary;+ (void)sleepUntilDate:(NSDate *)date;+ (void)sleepForTimeInterval:(NSTimeInterval)ti;+ (void)exit;+ (double)threadPriority;//设置线程优先级+ (BOOL)setThreadPriority:(double)p;@property double threadPriority NS_AVAILABLE(10_6, 4_0); // To be deprecated; use qualityOfService below@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0); // read-only after the thread is started+ (NSArray<NSNumber *> *)callStackReturnAddresses NS_AVAILABLE(10_5, 2_0);+ (NSArray<NSString *> *)callStackSymbols NS_AVAILABLE(10_6, 4_0);@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);@property (readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);+ (BOOL)isMainThread NS_AVAILABLE(10_5, 2_0); // reports whether current thread is main+ (NSThread *)mainThread NS_AVAILABLE(10_5, 2_0);//下面这种方法创建的线程需要手动开启线程- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);//取消线程执行- (void)cancel NS_AVAILABLE(10_5, 2_0);//开始线程执行- (void)start NS_AVAILABLE(10_5, 2_0);- (void)main NS_AVAILABLE(10_5, 2_0);// thread body method@end
测试代码如下:

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        [self useNSThread];}- (void) useNSThread {    [NSThread detachNewThreadSelector:@selector(task1) toTarget:self withObject:nil];    [NSThread detachNewThreadSelector:@selector(task2) toTarget:self withObject:nil];    //下面的方法,需要手动开启线程    NSThread * thread = [[NSThread alloc]initWithTarget:self selector:@selector(task3) object:nil];    [thread start];}
输出:

2015-11-09 10:30:56.826 04-多线程总结[1131:27495] -[ViewController task1],2015-11-09 02:30:56 +00002015-11-09 10:30:57.825 04-多线程总结[1131:27496] -[ViewController task2],2015-11-09 02:30:57 +00002015-11-09 10:30:58.822 04-多线程总结[1131:27497] -[ViewController task3],2015-11-09 02:30:58 +0000

(3)、NSOperation

NSOperation不能直接使用,只是定义了一些基本逻辑,它可以通过下面两个子类使用:

NSInvocationOperation继承自NSOperation

简单用法如下

- (void)viewDidLoad {    [super viewDidLoad];    // Do any additional setup after loading the view, typically from a nib.        [self useNSOperation];}-(void)useNSOperation{    //创建多个任务    NSInvocationOperation *opt1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task1) object:nil];    NSInvocationOperation *opt2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task2) object:nil];    NSInvocationOperation *opt3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task3) object:nil];    //创建一个线程队列    NSOperationQueue *queue = [[NSOperationQueue alloc]init];    //添加任务    [queue addOperation:opt1];    [queue addOperation:opt2];    [queue addOperation:opt3];    //添加任务    [queue addOperationWithBlock:^{        sleep(4);        NSLog(@"block:%@",[NSDate date]);    }];}
输出:

2015-11-09 10:35:04.399 04-多线程总结[1165:28878] -[ViewController task1],2015-11-09 02:35:04 +00002015-11-09 10:35:05.420 04-多线程总结[1165:28872] -[ViewController task2],2015-11-09 02:35:05 +00002015-11-09 10:35:06.439 04-多线程总结[1165:28875] -[ViewController task3],2015-11-09 02:35:06 +00002015-11-09 10:35:07.394 04-多线程总结[1165:28886] block:2015-11-09 02:35:07 +0000

NSBlockOperation继承自NSOperation

简单用法:

    NSBlockOperation * blockOperation = [NSBlockOperation blockOperationWithBlock:^{        NSLog(@"block operation");    }];    [blockOperation setCompletionBlock:^{        NSLog(@"wancheng block");    }];    [blockOperation start];

(4)gcd

基本用法:

    //如果线程队列是同步的,那么无论加入线程队列的方式是同步加入还是异步加入,执行所有的任务肯定是同步执行    //要想所有的任务都异步执行,必须线程队列是异步队列,同时,加入的任务方式也是异步地        //创建线程队列    //第二个参数表示创建的队列是同步队列还是异步队列    //DISPATCH_QUEUE_SERIAL:同步队列    //DISPATCH_QUEUE_CONCURRENT:异步队列    #if NO    dispatch_queue_t qt = dispatch_queue_create("dzl1", DISPATCH_QUEUE_CONCURRENT);//dzl1是线程名称        //async是异步地将一个任务(Blocks)加到队列中    dispatch_async(qt, ^{        [self task1];    });    dispatch_async(qt, ^{        [self task2];    });    dispatch_async(qt, ^{        [self task3];    });#endif    #if NO    //线程队列是异步地    dispatch_queue_t qt = dispatch_queue_create("dzl2", DISPATCH_QUEUE_CONCURRENT);        //sync是同步地将一个任务(Blocks)加到队列中    dispatch_sync(qt, ^{        [self task1];    });    dispatch_sync(qt, ^{        [self task2];    });    dispatch_sync(qt, ^{        [self task3];    });#endif
异步加入输入为:

2015-11-09 11:16:33.872 04-多线程总结[1540:41715] -[ViewController task1],2015-11-09 03:16:33 +00002015-11-09 11:16:34.870 04-多线程总结[1540:41672] -[ViewController task2],2015-11-09 03:16:34 +00002015-11-09 11:16:35.874 04-多线程总结[1540:41675] -[ViewController task3],2015-11-09 03:16:35 +0000

同步加入输出为:

2015-11-09 11:17:14.431 04-多线程总结[1555:42141] -[ViewController task1],2015-11-09 03:17:14 +00002015-11-09 11:17:16.440 04-多线程总结[1555:42141] -[ViewController task2],2015-11-09 03:17:16 +00002015-11-09 11:17:19.444 04-多线程总结[1555:42141] -[ViewController task3],2015-11-09 03:17:19 +0000

获取系统线程队列:

    //标准用法    //系统自带的线程队列        dispatch_async(dispatch_get_global_queue(0, 0), ^{        NSLog(@"this is global queue");    });        dispatch_async(dispatch_get_main_queue(), ^{        NSLog(@"this is main queue");    });
输出:

2015-11-09 11:45:14.676 04-多线程总结[1686:46905] this is global queue2015-11-09 11:45:14.683 04-多线程总结[1686:46797] this is main queue

线程组:

    //线程组的作用,用来监视一组任务的执行完成状态    dispatch_group_t gt = dispatch_group_create();    //创建一个线程队列    dispatch_queue_t qt = dispatch_queue_create("dzl", DISPATCH_QUEUE_SERIAL);    dispatch_group_async(gt, qt, ^{        [self task1];    });    dispatch_group_async(gt, qt, ^{        [self task2];    });    dispatch_group_async(gt, qt, ^{        [self task3];    });        //所有在线程组中的任务执行完成以后,调用以下方法    dispatch_group_notify(gt, dispatch_get_global_queue(2, 0), ^{        NSLog(@"gt中的所有任务已经执行完成");    });

输出:

2015-11-09 11:49:26.947 04-多线程总结[1746:48790] -[ViewController task1],2015-11-09 03:49:26 +00002015-11-09 11:49:28.955 04-多线程总结[1746:48790] -[ViewController task2],2015-11-09 03:49:28 +00002015-11-09 11:49:31.961 04-多线程总结[1746:48790] -[ViewController task3],2015-11-09 03:49:31 +00002015-11-09 11:49:31.962 04-多线程总结[1746:48793] gt中的所有任务已经执行完成

中断分组任务:

    dispatch_queue_t qt = dispatch_queue_create("com", DISPATCH_QUEUE_CONCURRENT);    dispatch_async(qt, ^{        [self task1];    });    dispatch_async(qt, ^{        [self task2];    });        //中断:有一个前提,线程队列(即qt)必须是自己创建的:不能用系统自带的线程队列    dispatch_barrier_async(qt, ^{        NSLog(@"++++++++++++++");    });        dispatch_async(qt, ^{        [self task3];    });    dispatch_async(qt, ^{        NSLog(@"---%@",[NSDate date]);    });
输出:

2015-11-09 11:51:57.235 04-多线程总结[1769:49646] -[ViewController task1],2015-11-09 03:51:57 +00002015-11-09 11:51:58.238 04-多线程总结[1769:49643] -[ViewController task2],2015-11-09 03:51:58 +00002015-11-09 11:51:58.243 04-多线程总结[1769:49643] ++++++++++++++2015-11-09 11:51:58.244 04-多线程总结[1769:49646] ---2015-11-09 03:51:58 +00002015-11-09 11:52:01.287 04-多线程总结[1769:49643] -[ViewController task3],2015-11-09 03:52:01 +0000

延时任务:

    //DISPATCH_TIME_NOW  开始时间    //接着的参数表示从当前时间向后延时多长时间见    dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5ull);    //第一个参数是执行该任务的时间点    //第二个参数是在哪个线程队列中执行    //第三个参数是任务    dispatch_after(time, dispatch_get_main_queue(), ^{        //5秒后背景变为紫色        self.view.backgroundColor = [UIColor purpleColor];    });

dispatch_apply:

dispathc_apply 是dispatch_sync 和dispatch_group的关联API.它以指定的次数将指定的Block加入到指定的队列中。并等待队列中操作全部完成。输出 顺序不确定,因为它是并行执行的(dispatch_get_global_queue是并行队列),实际上,如果 dispatch_apply 换成串行队列上,则会依次输出index,但这样会违背了我们想并行提高执行效率的初衷。

测试代码:

    NSMutableArray *_dataArray = [[NSMutableArray alloc]init];    for (int i = 0; i<20000; i++) {        [_dataArray addObject:[NSString stringWithFormat:@"model %d",i]];    }    //处理互相之间不影响的相似操作,和下标的次序没有关系    NSLog(@"--%@",[NSDate date]);    dispatch_apply(_dataArray.count, dispatch_get_global_queue(0, 0), ^(size_t n) {        NSLog(@"%@",_dataArray[n]);    });    NSLog(@"==%@",[NSDate date]);    NSLog(@"--%@",[NSDate date]);    for (NSString *str in _dataArray) {        NSLog(@"%@",str);    }    NSLog(@"==%@",[NSDate date]);
输出:

2015-11-09 12:09:28.899 04-多线程总结[1868:53819] --2015-11-09 04:09:28 +00002015-11-09 12:09:28.900 04-多线程总结[1868:53819] model 02015-11-09 12:09:28.900 04-多线程总结[1868:53819] model 22015-11-09 12:09:28.900 04-多线程总结[1868:53926] model 12015-11-09 12:09:28.900 04-多线程总结[1868:53819] model 32015-11-09 12:09:28.900 04-多线程总结[1868:53926] model 42015-11-09 12:09:28.900 04-多线程总结[1868:53819] model 52015-11-09 12:09:28.900 04-多线程总结[1868:53819] model 72015-11-09 12:09:28.901 04-多线程总结[1868:53819] model 82015-11-09 12:09:28.901 04-多线程总结[1868:53819] model 92015-11-09 12:09:28.900 04-多线程总结[1868:53926] model 62015-11-09 12:09:28.901 04-多线程总结[1868:53819] model 10..................2015-11-09 12:10:23.760 04-多线程总结[1868:53819] model 199972015-11-09 12:10:23.760 04-多线程总结[1868:53926] model 199962015-11-09 12:10:23.760 04-多线程总结[1868:53819] model 199982015-11-09 12:10:23.760 04-多线程总结[1868:53926] model 199992015-11-09 12:10:23.761 04-多线程总结[1868:53819] ==2015-11-09 04:10:23 +00002015-11-09 12:10:23.762 04-多线程总结[1868:53819] --2015-11-09 04:10:23 +00002015-11-09 12:10:23.762 04-多线程总结[1868:53819] model 02015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 12015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 22015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 32015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 42015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 52015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 62015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 72015-11-09 12:10:23.763 04-多线程总结[1868:53819] model 8..................2015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199922015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199932015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199942015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199952015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199962015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199972015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199982015-11-09 12:11:26.234 04-多线程总结[1868:53819] model 199992015-11-09 12:11:26.234 04-多线程总结[1868:53819] ==2015-11-09 04:11:26 +0000

dispatch_apply 完成两万次执行时间:55s

for 循环完成两万次执行时间:63s

我测试用的是虚拟机,真机dispatch_apply大概六七秒,for将近十秒,根据不同机器测出的数据肯定不一样,但是总的说明dispatch_apply比for循环快,但是dispatch_apply的执行时无序的。





0 0