iOS 多线程研究11

今天谈到多线程,那么就来说说多线程。

多线程简介。

第一、为什么使用多线程?

第二、怎么使用多线程?

第三、多线程都有哪些实现方式?

第四、多线程之间怎么实现通信的?

第五、使用多线程有什么缺点?有什么优点?

第六、使用多线程中应该注意什么?

下面一点一点来进行解决:

线程简介:

首先需要理解进程和线程这2个概念。

所谓进程对应的是一个应用程序,负责开辟内存空间供应用程序使用,但是进程不能执行任务(指令)。一个进程至少包含一条线程,线程是程序的执行流。
•iOS程序启动时,在创建一个进程的同时, 会开始运行一个线程,该线程被称为主线程
系统中的每一个进程都有自己独立的虚拟内存空间,而同一个进程中的多个线程则共用进程的内存空间
•每创建一个新的线程,都会消耗一定内存和CPU时间
•当多个线程对同一个资源出现争夺的时候需要注意线程安全问题

第一、为什么使用多线程?

将耗时、轮询或者并发需求高等任务分配到其他线程执行,并由主线程负责统一更新界面会使得应用程序更加流畅,用户体验更好,例如网络请求,播放游戏的背景音乐等。
第二、怎么使用多线程?
第三、多线程的实现方式?

IOS 中的多线程包括一下三种方法:NSThread,NSOpreation,GCD(grand central dispatch).

先来看看NSThread:

[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];  
NSThread* myThread = [[NSThread alloc] initWithTarget:self  
                                        selector:@selector(doSomething:)  
                                        object:nil];  
[myThread start];  

selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。

target  :selector消息发送的对象

argument:传输给target的唯一参数,也可以是nil

第一种方式会直接创建线程并且开始运行线程,第二种方式是先创建线程对象,然后再运行线程操作,在运行线程操作前可以设置线程的优先级等线程信息。

再看看NSOperation:

NSOperation和NSOperationQueue

  NSOperation 这个类必须要继承并重写里面的方法,才能够使用,不能直接使用NSOperation来实例化对象。

  1、一个继承自  NSOperation的操作类,该类的实现中必须有 - (void)main方法的。

  2、使用NSOperation的最简单方法就是将其放入NSOperationQueue中。

    一旦一个操作被加入队列,该队列就会启动并开始处理它(即调用该操作类的main方法)。一旦该操作完成队列就会释放它。

     self.queue = [[NSOperationQueue allocinit];

      ArticleParseOperation *parser = [[ArticleParseOperation allocinitWithData:filePath delegate:self];

      [queue addOperation:parser];

  3、可以给操作队列设置最多同事运行的操作数: [queue setMaxConcurrentOperationCount:2];

GCD:grand central dispatch:

是一套低层API,提供了一种新的方法来进行并发程序编写。从基本功能上讲,GCD有点像NSOperationQueue,他们都允许程序将任务切分为多个单一任务然后提交至工作队列来并发地或者串行地执行。GCD比之NSOpertionQueue更底层更高效,并且它不是Cocoa框架的一部分。

除了代码的平行执行能力,GCD还提供高度集成的事件控制系统。可以设置句柄来响应文件描述符、mach ports(Mach port 用于 OS X上的进程间通讯)、进程、计时器、信号、用户生成事件。这些句柄通过GCD来并发执行。

GCD的API很大程度上基于block,当然,GCD也可以脱离block来使用,比如使用传统c机制提供函数指针和上下文指针。实践证明,当配合block使用时,GCD非常简单易用且能发挥其最大能力。

GCD提供很多超越传统多线程编程的优势:

  1. 易用: GCD比之thread跟简单易用。由于GCD基于work unit而非像thread那样基于运算,所以GCD可以控制诸如等待任务结束监视文件描述符周期执行代码以及工作挂起等任务。基于block的血统导致它能极为简单得在不同代码作用域之间传递上下文。
  2. 效率: GCD被实现得如此轻量和优雅,使得它在很多地方比之专门创建消耗资源的线程更实用且快速。这关系到易用性:导致GCD易用的原因有一部分在于你可以不用担心太多的效率问题而仅仅使用它就行了。
  3. 性能: GCD自动根据系统负载来增减线程数量,这就减少了上下文切换以及增加了计算效率。
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self goDoSomethingLongAndInvolved];
        NSLog(@"Done doing something long and involved");
});

  

你很有可能希望在任务完成时更新界面,这就意味着需要在主线程中执行一些代码。你可以简单地完成这个任务——使用嵌套的dispatch,在外层中执行后台任务,在内层中将任务dispatch到main queue:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        [self goDoSomethingLongAndInvolved];
        dispatch_async(dispatch_get_main_queue(), ^{
            [textField setStringValue:@"Done doing something long and involved"];
        });
});

  

 GCD:         http://cache.baiducontent.com/c?m=9f65cb4a8c8507ed4fece763104e90275f15d7342bd7a74e3983d81f84642c101a39feeb797f4519d0cf766607ad4248afad762438587df68cc8f91f8ced&p=882a9545d19d08fc57efcf0c525781&newp=9b769a47928c5bff57ed94795f00a5231610db2151dcd75130ce&user=baidu&fm=sc&query=ios+gcd&qid=&p1=2

    

第五、线程间如何通信呢?

线程同步文章:http://blog.csdn.net/lifengzhong/article/details/7487505

线程同步

在以下两种基本情况下,线程之间需要相互通信:

  • 需要让多个线程同时访问一个共享资源,同时不能破坏资源的完整性;
  • 一个线程需要通知其它线程某项任务已经完成

什么情况下使用线程同步:

当一个线程需要用到另外一个线程执行完之后才会有的数据的时候,一般会使用线程的同步;

基本思路是,首先要创建公用的NSCondition实例。

使用NSCondition,实现多线程的同步,即,可实现生产者消费者问题。

  • 消费者取得锁,取产品,如果没有,则wait,这时会释放锁,直到有线程唤醒它去消费产品;
  • 生产者制造产品,首先也是要取得锁,然后生产,再发signal,这样可唤醒wait的消费者。
- (IBAction)didClickTest:(id)sender {
    _publicCondition = [[NSCondition alloc]init];
    _products = [[NSMutableArray alloc] init];

    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(didClickCreateSCZ:) object:nil];
   
    NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(didClickCreateXFZ:) object:nil];
    [thread1 start];
    [thread2 start];
    
}
- (IBAction)didClickCreateSCZ:(id)sender {
    [_publicCondition lock];
    while ([_products count] == 0) {
        NSLog(@"wait for products");
        [_publicCondition wait];
    }
    [_products removeObjectAtIndex:0];
    NSLog(@"comsume a product");
    [_publicCondition unlock];
}

- (IBAction)didClickCreateXFZ:(id)sender {
    [_publicCondition lock];
    [_products addObject:[[NSObject alloc] init]];
    NSLog(@"produce a product");
    [_publicCondition signal];
    [_publicCondition unlock];
}

  

第五、线程间是如何通信的呢? 

一般而言,应用程序中的一个次要线程总是为主线程执行特定的任务,这样,主线程和次要线程间必定有一个信息传递的渠道,也就是主线程和次要线程间要进行通信。这种线程间的通信不但是难以避免的,而且在多线程编程中也是复杂和频繁的,下面将进行说明。

1.使用全局变量进行通信

由于属于同一个进程的各个线程共享操作系统分配该进程的资源,故解决线程间通信最简单的一种方法是使用全局变量。对于标准类型的全局变量,我们建议使用volatile 修饰符,它告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变。如果线程间所需传递的信息较复杂,我们可以定义一个结构,通过传递指向该结构的指针进行传递信息。

原文地址:https://www.cnblogs.com/yinyakun/p/3581151.html