多线程

作者: 叫我小黑 | 来源:发表于2018-10-23 21:22 被阅读0次

    线程的注意点

    1.不要同时开太多的线程(1~3条线程即可,不要超过5条)
    2.线程概念
    (1)主线程 : UI线程,显示、刷新UI界面,处理UI控件的事件
    (2)子线程 : 后台线程,异步线程
    3.不要把耗时的操作放在主线程,要放在子线程中执行

    iOS的三种多线程技术

    NSThread

    • 使用NSThread对象建立一个线程非常方便
    • 但是!要使用NSThread管理多个线程非常困难,不推荐使用
    • 技巧!使用[NSThread currentThread]跟踪任务所在线程,适用于这三种技术

    NSOperation/NSOperationQueue

    • 是使用GCD实现的一套Objective-C的API
    • 是面向对象的线程技术
    • 提供了一些在GCD中不容易实现的特性,如:限制最大并发数量、操作之间的依赖关系

    GCD —— Grand Central Dispatch

    • 是基于C语言的底层API
    • 用Block定义任务,使用起来非常灵活便捷
    • 提供了更多的控制能力以及操作队列中所不能使用的底层函数

    NSThread

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

    (1)先创建,后启动

    // 创建 
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(download:) object:nil];
    // 启动
    [thread start];
    

    (2)创建完自动启动

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

    (3)隐式创建(自动启动)

    [self performSelectorInBackground:@selector(download:) 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(Grand Central Dispatch)

    1.队列和任务

    (1) 任务 :需要执行什么操作

    • 用block来封装任务

    (2)队列 :存放任务

    • 全局的并发队列 : 可以让任务并发执行
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    
    • 自己创建的串行队列 : 让任务一个接着一个执行
    dispatch_queue_t queue = dispatch_queue_create("cn.heima.queue", NULL);
    
    • 主队列 : 让任务在主线程执行
    dispatch_queue_t queue = dispatch_get_main_queue();
    
    2.执行任务的函数

    (1)同步执行 : 不具备开启新线程的能力
    dispatch_sync...
    (2)异步执行 : 具备开启新线程的能力
    dispatch_async...

    3.常见的组合

    (1)dispatch_async + 全局并发队列
    (2)dispatch_async + 自己创建的串行队列

    4.线程间的通信
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       // 执行耗时的异步操作... 
       dispatch_async(dispatch_get_main_queue(), ^{
           // 回到主线程,执行UI刷新操作
       });
    });
    
    5.GCD的所有API都在libdispatch.dylib,Xcode会自动导入这个库

    主头文件 : #import <dispatch/dispatch.h>

    6.延迟执行

    (1) perform....

    // 3秒后自动回到当前线程调用self的download:方法,并且传递参数:@"http://555.jpg"
    [self performSelector:@selector(download:) withObject:@"http://555.jpg" afterDelay:3];
    

    (2) dispatch_after...

    // 任务放到哪个队列中执行
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    double delay = 3; // 延迟多少秒
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC)), queue, ^{
        // 3秒后需要执行的任务
    });
    
    7.一次性代码
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 这里面的代码,在程序运行过程中,永远只会执行1次
    });
    

    单例模式(懒汉式)

    1.ARC
    @interface HMDataTool : NSObject
    + (instancetype)sharedDataTool;
    @end
    
    @implementation HMDataTool
    // 用来保存唯一的单例对象
    static id _instace;
    
    + (id)allocWithZone:(struct _NSZone *)zone
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instace = [super allocWithZone:zone];
        });
        return _instace;
    }
    
    + (instancetype)sharedDataTool
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instace = [[self alloc] init];
        });
        return _instace;
    }
    
    - (id)copyWithZone:(NSZone *)zone
    {
        return _instace;
    }
    @end
    
    MRC
    @interface HMDataTool : NSObject
    + (instancetype)sharedDataTool;
    @end
    
    @implementation HMDataTool
    // 用来保存唯一的单例对象
    static id _instace;
    
    + (id)allocWithZone:(struct _NSZone *)zone
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instace = [super allocWithZone:zone];
        });
        return _instace;
    }
    
    + (instancetype)sharedDataTool
    {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            _instace = [[self alloc] init];
        });
        return _instace;
    }
    
    - (id)copyWithZone:(NSZone *)zone
    {
        return _instace;
    }
    
    - (oneway void)release {
        
    }
    
    - (id)retain {
        return self;
    }
    
    - (NSUInteger)retainCount {
        return 1;
    }
    
    - (id)autorelease {
        return self;
    }
    @end
    

    NSOperation和NSOperationQueue

    1.队列的类型

    (1) 主队列
    [NSOperationQueue mainQueue]
    添加到"主队列"中的操作,都会放到主线程中执行
    (2) 非主队列
    [[NSOperationQueue alloc] init]
    添加到"非主队列"中的操作,都会放到子线程中执行

    2.队列添加任务
    - (void)addOperation:(NSOperation *)op;
    - (void)addOperationWithBlock:(void (^)(void))block;
    
    3.常见用法

    (1) 设置最大并发数

    - (NSInteger)maxConcurrentOperationCount;
    - (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
    

    (2) 队列的其他操作
    取消所有的操作
    - (void)cancelAllOperations;
    暂停所有的操作
    [queue setSuspended:YES];
    恢复所有的操作
    [queue setSuspended:NO];

    4.操作之间的依赖

    NSOperation之间可以设置依赖来保证执行顺序
    [operationB addDependency:operationA];
    操作B依赖于操作A,等操作A执行完毕后,才会执行操作B。
    注意:不能相互依赖,比如A依赖B,B依赖A;可以在不同queue的NSOperation之间创建依赖关系

    5.线程之间的通信
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        // 1.执行一些比较耗时的操作
        // 2.回到主线程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            //主线程操作
        }];
    }];
    

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

    1.perform...
    [self performSelectorOnMainThread:<#(SEL)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#>];
    
    2.GCD
    dispatch_async(dispatch_get_main_queue(), ^{
        //主线程操作
    });
    
    3.NSOperationQueue
    [[NSOperationQueue mainQueue] addOperationWithBlock:^{
        //主线程操作
    }];
    

    相关文章

      网友评论

          本文标题:多线程

          本文链接:https://www.haomeiwen.com/subject/tihzzftx.html