多线程编程

来源:互联网 发布:怎样写淘宝直通车标题 编辑:程序博客网 时间:2024/06/08 14:25
</pre><p>首先要强调的是数组的并行和串行两种执行方式。</p><p></p><pre name="code" class="objc"> NSArray *array = @[@1,@2,@3,@4,@5];        //数组排序:    //NSSortStable:串行,在排序执行的时候,程序为顺序结构执行,排序不执行完成,后期的代码不会运行。(耗时间,但结果安全)    //NSSortConcurrent:并行,在程序执行的时候,程序为多线程方式,排序方法执行的时候,下面的代码也同步执行。(节省时间,结果不安全)    [array sortedArrayWithOptions:NSSortStable usingComparator:^NSComparisonResult(id obj1, id obj2) {        return [obj1 compare:obj2];    }];        NSLog(@"%@",array);

现在开始步入正题,这节课我们讲的是iOS高级编程中的多线程编程。


程序是什么?

程序是由源代码生成的可执行应用。

进程是什么?

进程:一个正在运行的程序可以看错一个进程。进程拥有独立运行所需的全部资源。

线程是什么?

线程是程序中独立运行的代码段。

程序,进程,线程之间的关系呢?

一个进程是由一个或多个线程组成,进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。


单线程?

每个正在运行的程序(即进程)至少包含一个线程,这个线程叫主线程。

主线程在程序启动时被创建,用于执行main函数。

只有一个主线程的程序,称作单线程程序。

主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。


多线程?

拥有多个线程的程序,称为多线程程序。

iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。

可以根据需要开辟若干子线程。

子线程和主线程都是独立的运行单元,各自的执行互不影响,因此能够并发执行。


单线程和多线程的区别?

单线程程序:只有一个线程,代码顺序执行,容易出现代码阻塞(页面假死)

多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。

注意:iOS中关于UI的添加和刷新必须在主线程中操作。


iOS平台下得多线程


多线程的种类

1.脱离线程
2.非脱离线程


iOS多线程实现种类

NSObect 实现异步后台执行

NSObject中存在了一个最简单的后台执行的方法


//NSObject 多线程方式 后台执行某个方法    [self performSelectorInBackground:@selector(calculate) withObject:nil];

NSThread

是一个轻量级的多线程,它有以下两种创建方法。

    //NSThread 多线程方式    //方式1 初始化一个子线程,但需要手动开启    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(calculate) object:nil];    [thread1 start]; //开启子线程,concel取消子线程     //方式2 初始化一个子线程并自动开启     [NSThread detachNewThreadSelector:@selector(calculate) toTarget:self withObject:nil];

注意:在多线程方法中需要添加自动释放池

          在应用程序打开的时候,系统会自动为主线程创建一个自动释放池

          我们手动创建的子线程需要我们手动添加自动释放池!


NSOperationQueue

NSOperation类,在MVC中属于M,是用来封装单个任务相关的代码和数据的抽象类。

因为它是抽象的,不能够直接使用这个类,而是使用子类(NSInvocationOperation或NSBlockOperation)来执行实际任务

NSOperation(含子类),只是一个操作,本身无主线程、子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。

NSInvocationOperation是NSOperation的子类

封装了执行操作的target和要执行的action


NSBlockOperation是NSOperation的子类

封装了需要执行的代码块


NSOperationQueue是操作队列,他用来管理一组Operation对象的执行,会根据需要自动为Operation开辟合适数量的线程,以完成任务的并行执行。

其中NSOperation可以调节它在队列中的优先级。

当最大并发数设置为1的时候,能实现线程同步。


    //NSOperation/NSOperationQueue 多线程方式   //方式一NSInvocationOperation    NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printNumber) object:nil];#warning 需要手动开启 辅助实现多线程//    [invocation start];        //方式二NSBlockOperation Block会持有内部变量    __weak typeof(self) temp = self;    NSBlockOperation *block = [NSBlockOperation blockOperationWithBlock:^{        [temp printAnotherGroupNumber];    }];//    [block start];        //可以通过NSOperationQueue创建队列,向队列中添加操作,完成多任务同时执行,当最大并发数为1,变成了串行。    NSOperationQueue *queue = [[NSOperationQueue alloc]init];#warning 一定要提前设置好并发数 决定是否能够并发进行 如上所述    [queue setMaxConcurrentOperationCount:1];    [queue addOperation:invocation];    [queue addOperation:block];- (void)printNumber{    for (int i =0; i<10; i++) {        NSLog(@"1");    }}- (void)printAnotherGroupNumber{    for (int i =0; i<10; i++) {        NSLog(@"2");    }}- (void)calculate{#warning 一定要写自动释放池    @autoreleasepool {        NSArray *array = @[@1,@2,@3,@4,@5];                for (int i = 0; i <10; i++) {            array = [array arrayByAddingObjectsFromArray:array];        }                NSLog(@"%@",array);        self.view.backgroundColor = [UIColor redColor];        NSLog(@"%d",[NSThread isMainThread]);    }}- (void)test{    @autoreleasepool {        NSArray *array = @[@1,@2,@3,@4,@5];                for (int i = 0; i <18; i++) {            array = [array arrayByAddingObjectsFromArray:array];        }                NSLog(@"%@",array);        self.view.backgroundColor = [UIColor blackColor];        NSLog(@"%d",[NSThread isMainThread]);        NSLog(@"这是另外一个线程的方法");    }}

GCD (Grand Central Dispatch)  中央调度
     1.主队列
     2.全局队列
     3.自定义队列{串行队列,并行队列}

GCD简介

Grand Central Dispatch 简称(GCD)是苹果公司开发的技术。

以优化应用程序支持多核心处理器和其他的对称多处理系统的系统。

GCD属于函数级的多线程,性能更高,功能也更加强大。

它首次发布在OS X 10.6 iOS 4及以上也可用

GCD核心概念

任务:具有一定功能的代码段。一般是一个Block或者函数。

分发队列:GCD以队列的方式进行工作,FIFO(First In First Out)

GCD会根据分发队列的类型,创建合适数量的线程执行队列中的任务。

 

1.主队列

//获取主队列    dispatch_queue_t mainQueue = dispatch_get_main_queue();    //向主队列中添加任务 串行队列    dispatch_async(mainQueue, ^{        NSLog(@"第一个任务...");    });    dispatch_async(mainQueue, ^{        NSLog(@"第二个任务...");    });    dispatch_async(mainQueue, ^{        NSLog(@"第三个任务...");    });
延时执行

//设置延时执行    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{        NSLog(@"这是五年后的你");    });        dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC));    //NSEC_PER_MSEC 毫秒    //NSEC_PER_USEC 微秒    dispatch_after(time, mainQueue, ^{        NSLog(@"这是十年后的你");    });

不要再主线程中加入延迟,会造成阻塞。

串行与并行没有关系
主队列与全局队列都是单例,主队列串行,全局队列并行,都是直接获取,直接使用,不需要创建,也就是一直存在。


2.全局队列

//获取全局队列    dispatch_queue_t globelQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    //向全局队列中添加任务,串行队列    dispatch_async(globelQueue, ^{        NSLog(@"我");    });    dispatch_async(globelQueue, ^{        NSLog(@"爱");    });    dispatch_async(globelQueue, ^{        NSLog(@"你");    });

重复执行

    dispatch_apply(3, globelQueue, ^(size_t t) {        NSLog(@"重要的事情说三遍");        NSLog(@"%lu",t);    });
分组任务

//分组任务    dispatch_group_t group = dispatch_group_create();    dispatch_group_async(group, globelQueue, ^{        NSLog(@"第一分组第一小队");    });    dispatch_group_async(group, globelQueue, ^{        NSLog(@"第一分组第二小队");    });    dispatch_group_async(group, globelQueue, ^{        NSLog(@"第一分组第三小队");    });
    //与添加在队列的位置有关系,当处于队列末尾的时候,最后执行。    dispatch_group_notify(group, globelQueue, ^{        NSLog(@"你们先来。我不着急。");    });

3.自定义队列

自定义串行队列

 //自定义串行队列    //第一个参数:队列标识符,可以获取到某一队列的标识符。    //第二个参数:队列的类型(串行或者并行)    dispatch_queue_t serialQueue = dispatch_queue_create("sss", DISPATCH_QUEUE_SERIAL);    //添加task    dispatch_async(serialQueue, ^{        NSLog(@"王");    });    dispatch_async(serialQueue, ^{        NSLog(@"颜");    });    dispatch_async(serialQueue, ^{        NSLog(@"华");    });
自定义并行队列

   //自定义并行队列    dispatch_queue_t concurrentQueue = dispatch_queue_create("ccc", DISPATCH_QUEUE_CONCURRENT);    dispatch_async(concurrentQueue, ^{        NSLog(@"111");    });    //将任务添加到队列中,Block不执行完,下面代码不会执行。    dispatch_sync(concurrentQueue, ^{        int sum = 0;        for (int i= 0 ; i<635500000; i++) {            sum += i;        }        NSLog(@"都等着我");    });        //将此函数添加到队列的任务中,需要等其执行完成后才可以执行其他队列的任务。    //前提:自定义并行队列。    dispatch_barrier_async(concurrentQueue, ^{        int sum = 0;        for (int i= 0 ; i<635500000; i++) {            sum += i;        }        NSLog(@"让我先来");    });    dispatch_async(concurrentQueue, ^{        NSLog(@"222");    });

//GCD 可以使用此函数,向队列中添加函数,让函数执行。    //函数类型 void(*)(void *)    dispatch_async_f(concurrentQueue, "string", function);

 //dispatch_once 添加的任务 在整个程序运行期间只会执行一次(重复添加无效)    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        NSLog(@"哈哈哈哈");    });    dispatch_once(&onceToken, ^{        NSLog(@"哈哈哈哈");    });    dispatch_once(&onceToken, ^{        NSLog(@"哈哈哈哈");    });
上述方法 可以用在单例中

伪单例方法

+ (instancetype)shareSingleton{    static Singleton *singleton = nil;    static dispatch_once_t onceToken;    dispatch_once(&onceToken, ^{        singleton = [self new];    });    return singleton;}

   线程间通信

分为两种:

主线程进入子线程

子线程回到主线程

方法:

dispatch_get_main_queue()                    GCD

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait  NSObject


线程互斥

线程互斥场景

线程互斥是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。

互斥无法限制访问者对资源的访问顺序,即访问是无序的,因此需要加上互斥锁来进行顺序访问,最具有代表性的就是买票系统!

NSLock类能协助完成互斥操作。


总结

NSThread、NSOperationQueue、NSObject、GCD都能实现多线程。

GCD是苹果提供的性能更高的方式。

线程尽管提升了性能,但是存在一些访问限制,比如线程同步,线程互斥等。




0 0
原创粉丝点击