zoukankan      html  css  js  c++  java
  • iOS多线程技术---pthread、NSThread、NSOperation、GCD

    多线程技术

    process进程:在系统中运行的一个应用程序;每个进程都是独立的;有专有的内存空间

    thread线程:程序的一段执行序列,进程的不部分;

                 特点:1、进程只分配内存空间,并不执行任务

                             2、每个进程至少有一个线程,该线程叫做主线程

                             3、线程是进程的基本执行单元,进程的所有任务都是在线程中执行

                             4、每个线程中得任务的执行都是串行的

     

    多线程并发:一个进程中多条线程并发执行任务;

                特点:   1、提高程序的执行效率,提高资源利用率

                            2、同一时间,CPU只能处理一条线程

                            3、多线程并发时,CPU在多条线程间快速切换

                            4、线程切换的 速度很快,就造成了多线程的并发执行

                            5、开启线程需要内存空间,线程太多会造成调度消耗太多资源

                            6、线程过多会降低每条线程被调度的频率(线程执行效率降低)

     

    多线程的应用:

            主线程:显示刷新UI界面、处理UI事件;耗时任务(如下载)放在子线程中

            判定方法在哪个线程中执行:NSLog(@“当前的线程:”,[NSThread currentThread]);

     

    四种多线程技术:pthread   NSThread   GCD  NSOperation

     

    1.pthread

          基于c语言的API ,可编写多平台应用,使用难度大,需要手动创建销毁线程,可自定义功能少

    pthread_t pthread;

    void *task(void *data){

    NSLog(@“当前子线程:%@“,NSThread currentThread];

    return 0;

    }

     

    pthread_create(&pthread,NULL,task,NULL);

     

    2.NSThread

    • 基于OC,相对于pthread使用简单,面向对象
    • 缺点:需要自己管理线程的生命周期,线程同步,加锁、开锁,管理多个线程比较困难

     

    手动创建线程的三种方法:

    1、NSThread实例方法:- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(id)argument NS_AVAILABLE(10_5, 2_0);(只创建

    2、NSThread类方法:+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument; (创建并运行

    3、NSThread实例方法:- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg NS_AVAILABLE(10_5, 2_0);

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

            object: 传给target的唯一参数,也可以为nil

            target: selector消息发送的对象 只有第一个能设置名字、优先级

    线程阻塞(延迟):

    • // sleep⽅法⼀:开始睡眠5秒钟

    [NSThread sleepForTimeInterval:5];

    • // sleep⽅法二:

    NSDate *date = [NSDate dateWithTimeIntervalSinceNow:3

    [NSThread sleepUntilDate:date];

    强制停止线程:

    [NSThread exit];

    其他常用方法:

    • +(NSThread *)mainThread; //获得主线程
    • -(BOOL)isMainThread;//判断是否是主线程
    • +(double)threadPriority;//获取线程优先级    优先级取值范围0.0~1.0 值越大优先级越高
    • +(BOOL)setThreadPriority:(double)p;//设置优先级
    • -(NSString*)name;//获取线程名字
    • -(void)setName:(NSString*)n;//设置线程名字

     

    线程的状态:

    • New(新建) -> Runnable(就绪) --> cpu开始调度当前线程 ---> Running(运行) ---> 调用 sleep方法 ---> Blocked(阻塞) ---> 移除线程池 ---> sleep执行完毕/到时 ---> 进入线程 池 ---> Runnable(就绪)
    • 如果线程任务执行完毕/异常/强制退出 ---> Dead(死亡)

    加锁:

    • 尽量避免使用@synchronized,也就是避免多个线程访问同一个资源,因为有了加锁、 解锁需要消耗比较大的cpu资源 
    • 加锁的前提:多个线程同时访问同一个资源的时候才需要加锁(互斥锁) 
    • 线程同步:多条线程在同一条线上执行(按顺序地执行任务) 
    • 尽量讲加锁、资源抢夺的业务逻辑交割服务器端处理,减少移动客户端的压力

    synchronized关键字

    1、synchronized关键字的作用域有二种:

    1)是某个对象实例内,synchronized aMethod(){}可以防止多个线程同时访问这个对象的synchronized方法(如果一个对象有多个synchronized方法,只要一个线程访问了其中的一个synchronized方法,其它线程不能同时访问这个对象中任何一个synchronized方法)。这时,不同的对象实例的 synchronized方法是不相干扰的。也就是说,其它线程照样可以同时访问相同类的另一个对象实例中的synchronized方法;

    2)是某个类的范围,synchronized static aStaticMethod{}防止多个线程同时访问这个类中的synchronized static 方法。它可以对类的所有对象实例起作用

    2、除了方法前用synchronized关键字,synchronized关键字还可以用于方法中的某个区块中,表示只对这个区块的资源实行互斥访问。用法是: synchronized(this){},它的作用域是当前对象;

    原子和非原子属性:

    • nonatomic: 非原子 —> 不会在set方法中加锁,这个是推荐方式,会占用资源少
    • atomic:原子 —> 在set方法中加锁,防止多个线程同时执行set方法

     

    线程间的通讯

    1.在一个进程中,线程往往不是孤立存在的,多个线程之间需要经常进行通信 

    2.线程间通讯的方式:

    • 一个线程传递数据给另一个线程
    • 在一个线程中执行完特定任务后,转到另一个线程继续执行任务

    子线程返回主线程的两种方法:

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

    - (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait

    ***********************************************************************************************

    3. GCD

     并行队列只有在执行多个异步任务的时候体现出来并发现象,因为在线程快速切换时体现出并行;

     同步执行的任务 会致使后面的任务提交阻塞;

    GCD:Grand Central Dispath 大中央调度

     
    • GCD的基本思想就是将操作(任务)放在队列中去执行
    • 队列负责调度任务执行所在的线程以及具体的执行时间
    • 队列的特点是先进先出,新添加至队列的操作(任务)都会排在队尾
     
    GCD的函数都是以dispatch开头的,dispatch的意思是“分配、调度”
     
    • 串行队列中的任务会按顺序执行
    • 并行队列中的任务通常会并发执行,而且无法确定任务的执行顺序
     
    dispatch_async表示异步操作,异步操作会新开辟线程来执行任务,而且无法确定任务的执行顺序
    dispatch_sync表示同步操作,同步操作不会新开辟线程
     
    1. 在串行队列中执行同步任务:不会新建线程,按顺序执行任务(毫无用处)
    2. 在串行队列中执行异步任务,会新建线程,按顺序执行任务(非常有用)
     
    1. 在并行队列中执行同步任务:不会新建线程,按顺序执行任务(几乎没用)
    2. 在并行队列中执行异步任务:会新建多个线程,但是无法确定任务的执行顺序(有用,但是很容易出错)
     
    全局队列
    • 全局队列是系统的,直接拿过来就可以用,与并行队列类似,但是不能指定队列的名字,调试时无法确认任务所在队列
    • 在全局队列中执行同步任务:不会新建线程,按顺序执行任务
    • 在全局队列中执行异步任务:会新建多个线程,但是无法确定任务的执行顺序
    主队列
    • 如果把任务放到主队列中进行处理,那么不论处理函数是异步的还是同步的都不会开启新的线程。
    • 每一个应用程序只有一个主线程即只有一个主队列
    • 为什么需要再主线程上执行任务呢?因为在ios开发中,所有UI的更新任务都必须在主线程上执行。
    • 主队列中的操作都是在主线程中执行的,不存在异步的概念
    • 在主线程中向 主队列中添加的同步操作会死锁

    线程阻塞(延迟):三种方法

     1 //过3秒后做一件事儿,这个做法会导致主线程阻塞,不提倡使用
     2 - (IBAction)sleepDelay:(id)sender
     3 {
     4     NSLog(@"3秒后干件事儿!");
     5     [NSThread sleepForTimeInterval:3];
     6     NSLog(@"干事儿中...");
     7 }
     8 - (IBAction)performAfterDelay:(id)sender
     9 {
    10     NSLog(@"3秒后干件事儿!");
    11     //在3秒后会启动一个线程去完成任务(调用方法task),此方法并不会阻塞
    12     [self performSelector:@selector(task) withObject:nil afterDelay:3];
    13     NSLog(@"主线程继续向下执行...");
    14 }
    15 - (void)task
    16 {
    17     NSLog(@"干活中...");
    18 }
    19 //使用GCD实现延迟执行
    20 - (IBAction)dispatchAfter:(id)sender
    21 {
    22     /*
    23      1秒 = 1000毫秒
    24      1毫秒 = 1000微秒
    25      1微秒 = 1000纳秒
    26      */
    27     //dispatch_time函数的第二个参数单位是纳秒
    28     NSLog(@"3秒钟后做事");
    29     dispatch_after(
    30                    /**
    31                     *  延迟的函数
    32                     *
    33                     *  @param DISPATCH_TIME_NOW 从现在起
    34                     *  @param int64_t           延迟描述
    35                     *    NSEC_PER_SEC 这个宏的意思是每秒多少纳秒
    36                     *  @return 无
    37                     */
    38         dispatch_time(DISPATCH_TIME_NOW, (int64_t)3 * NSEC_PER_SEC),
    39         dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),
    40         ^{
    41             NSLog(@"3秒后我开始做需要的事情啦!");
    42     });
    43 }
    View Code

    线程间的通讯:

    dispatch_async( dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 执⾏耗时的异步操作...
    dispatch_async(dispatch_get_main_queue(), ^{
    
    // 回到主线程,执⾏UI刷新操作
    });
    });  

    dispatch_once  参照:线程安全的单例  http://www.cnblogs.com/ChrisYu/p/4651114.html

    小结:

           无论什么队列和什么任务,线程的创建和回收不需要程序员参与,由队列来负责,程序员只需要面对队列和任务。GCD在后端管理这一个线程池,GCD不仅决定着Block代码块将在哪个线程中被执行,而且还可以根据可用的系统资源对这些线程进行管理,从而让开发者从线程管理的工作中解放出来,通过GCD这种集中的管理线程,缓解了大量的线程被创建的问题

     

     

    4. NSOperation

     

     

     

    单词:

    1. global   ge(0) lao(1) bao(3)  全局

    2. concurrent   并发

    3. queue  队列

     

     

    作业:

    1. 从网上下载图片并显示到界面上。

    要求,下载过程中界面不能死。

    用GCD做

     

    2. 了解一个第三方框架SDWebImage

     1 - (IBAction)serialOperation
     2 {
     3     //默认OperationQueue中的线程都是并行的
     4     NSOperationQueue *queue = [[NSOperationQueue alloc]init];
     5     NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printPlusSignal) object:nil];
     6 //    [operation1 start];//不会启动线程,直接在主线程中执行
     7     [queue addOperation:operation1];
     8     NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printMinusSignal) object:nil];
     9     //[operation2 start];
    10     //线程二要依赖线程一,所以线程2会等线程一结束了再执行,按此方式可以让两个线程串行执行
    11     [operation2 addDependency:operation1];
    12     [queue addOperation:operation2];
    13 }
    14 
    15 - (void)printPlusSignal
    16 {
    17     for (int i=0; i<10; i++) {
    18         [NSThread sleepForTimeInterval:1];
    19         NSLog(@"++++++++++++++");
    20     }
    21 }
    22 
    23 - (void)printMinusSignal
    24 {
    25     for (int i=0; i<10; i++) {
    26         [NSThread sleepForTimeInterval:1];
    27         NSLog(@"----------------");
    28     }
    29 }
    30 
    31 - (IBAction)concurrentQueue:(id)sender
    32 {
    33     //默认OperationQueue中的线程都是并行的
    34     NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    35     NSInvocationOperation *operation1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printPlusSignal) object:nil];
    36    
    37     [queue addOperation:operation1];
    38     NSInvocationOperation *operation2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(printMinusSignal) object:nil];
    39 
    40     [queue addOperation:operation2];
    41 }
    42 
    43 //使用Block提交任务给OperationQueue
    44 - (IBAction)blockQueue
    45 {
    46     NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    47     //CallBack 回调
    48     NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    49         for (int i=0; i<10; i++) {
    50             [NSThread sleepForTimeInterval:1];
    51             NSLog(@"++++++++++++++");
    52         }
    53     }];
    54     [queue addOperation:operation1];
    55     
    56     NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    57         for (int i=0; i<10; i++) {
    58             [NSThread sleepForTimeInterval:1];
    59             NSLog(@"-------------");
    60         }
    61     }];
    62     [queue addOperation:operation2];
    63 }
    64 - (IBAction)mainQueue
    65 {
    66     NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    67     NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    68         NSLog(@"在子线程中-----%@", [NSThread currentThread]);
    69         //获取主队列(回到主线程)
    70         NSOperationQueue *mainQueue = [NSOperationQueue mainQueue];
    71         NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    72             NSLog(@"在主线程中?-----%@", [NSThread currentThread]);
    73         }];
    74         [mainQueue addOperation:operation2];
    75     }];
    76     [queue addOperation:operation];
    77 }
    View Code
  • 相关阅读:
    第十二章学习笔记
    UVa OJ 107 The Cat in the Hat (戴帽子的猫)
    UVa OJ 123 Searching Quickly (快速查找)
    UVa OJ 119 Greedy Gift Givers (贪婪的送礼者)
    UVa OJ 113 Power of Cryptography (密文的乘方)
    UVa OJ 112 Tree Summing (树的求和)
    UVa OJ 641 Do the Untwist (解密工作)
    UVa OJ 105 The Skyline Problem (地平线问题)
    UVa OJ 100 The 3n + 1 problem (3n + 1问题)
    UVa OJ 121 Pipe Fitters (装管子)
  • 原文地址:https://www.cnblogs.com/ChrisYu/p/4649968.html
Copyright © 2011-2022 走看看