iOS之多线程精髓

一个正在运行的程序叫做进程,线程是进程的基本执行单元。进程中的任务在线程中执行。

一个进程中默认有一条主线程,单一线程中任务执行是串行的。多条线程可以同时执行不同任务。


多线程原理

同一时间cpu只能处理一条线程,多线程并发执行,是CPU快速的在多条线程中切换形成的假象。


多线程的优点
能适当提高程序的执行效率
能适当提高资源利用率( CPU 、内存利用率)
多线程的缺点
开启线程需要占用一定的内存空间(默认情况下,主线程占用 1M ,子线程占用 512KB 如果开启大量的线程 会占用大量的内存空间,降低程序的性能
线程越多, CPU 在调度线程上的开销就越大
程序设计更加复杂:比如线程之间的通信、多线程的数据共享


主线程

主线程的主要作用
显示 \ 刷新 UI 界面
处理 UI 事件(比如点击事件、滚动事件、拖拽事件等)

主线程的使用注意
别将比较耗时的操作放到主线程中
耗时操作会卡住主线程,严重影响 UI 的流畅度,给用户一种“卡”的坏体验

ios实现多线程的方案
pthread
通用的线程API,使用难度大

NSThread
使用更加面向对象,简单易用可以直接操作。

GCD
旨在替代NSThread等线程技术
充分利用设备多核

NSOperation
基于GCD 比GCD多了一些更简单实用的功能,更加面向对象

NSThread

创建、启动线程

NSThread*thread = [[NSThread alloc] initWithTarget:self selector:@selector(run)object:nil];

[thread start];

+ (NSThread *)mainThread;//获得主线程

- (BOOL)isMainThread;//是否为主线程

+ (BOOL)isMainThread;//是否为主线程

- (void)setName:(NSString *)n;

- (NSString*)name;


创建线程后自动启动线程

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

隐式创建并启动线程

[self performSelectorInBackground:@selector(run)withObject:nil];

上述 2 种创建线程方式的优缺点
优点:简单快捷
缺点:无法对线程进行更详细的设置


启动线程

- (void)start;

//进入就绪状态 ->运行状态当线程任务执行完毕,自动进入死亡状态

阻塞 (暂停)线程

+ (void)sleepUntilDate:(NSDate*)date;

+ (void)sleepForTimeInterval:(NSTimeInterval)ti;

//进入阻塞状态

强制停止线程

+ (void)exit;

//进入死亡状态

注意:一旦线程停止(死亡)了,就不能再次开启任务


互斥锁使用格式

@synchronized(锁对象) { //需要锁定的代码  }

注意:锁定1份代码只用1把锁,用多把锁是无效的

互斥锁的优缺点
优点:能有效防止因多线程抢夺资源造成的数据安全问题
缺点:需要消耗大量的 CPU 资源

iOS 开发的建议
所有属性都声明为 nonatomic
尽量避免多线程抢夺同一块资源
尽量将加锁、资源抢夺的业务逻辑交给服务器端处理,减小移动客户端的压力


GCD

 优点:

    <1> GCD 能够自动利用更多的CPU的核数(双核/四核)!

    <2> GCD 会自动管理线程的生命周期.

  1> dispatch_async + 全局并发队列 (可以开启多条线程)

   2> dispatch_async + 自己创建的串行队列 (开启一条线程)



GCD开启多线程,
定制任务添加队列
同步 的方式执行任务

dispatch_sync(dispatch_queue_tqueue, dispatch_block_tblock);

queue :队列
block :任务
异步 的方式执行任务

dispatch_async(dispatch_queue_tqueue, dispatch_block_tblock);


使用dispatch_queue_create函数创建串行队列
使用 dispatch_get_global_queue 函数获得全局的并发队列
使用 dispatch_get_main_queue () 获得主队列


从子线程回到主线程

dispatch_async(

dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

   //执行耗时的异步操作...

     dispatch_async(dispatch_get_main_queue(),^{

        //回到主线程,执行UI刷新操作

        });

});


GCD延时,
iOS 常见的延时执行有 2 种方式
调用 NSObject 的方法

[self performSelector:@selector(run)withObject:nil afterDelay:2.0];

// 2秒后再调用selfrun方法

使用 GCD 函数

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(),^{

   //2秒后执行这里的代码...在哪个线程执行,跟队列类型有关

   

});


GCD单例

static dispatch_once_t onceToken;

dispatch_once(&onceToken, ^{

   //只执行1次的代码(这里面默认是线程安全的)

});


ARC

提供 1 个类方法让外界访问唯一的实例

+ (instancetype)sharedMusicTool {

   if (_instance == nil) { //防止频繁加锁

          @synchronized(self) {

            if (_instance == nil) { //防止创建多次

               _instance = [[self alloc] init];

            }

        }

   }

   return _instance;

}

p 实现copyWithZone: 方法

- (id)copyWithZone:(struct _NSZone*)zone {

   return _instance;

}


非ARC下添加方法
ARC 中( MRC ),单例模式的实现 ARC 多了几个步骤)
实现内存管理方法

- (id)retain { return self; }

- (NSUInteger)retainCount { return 1; }

- (oneway void)release{}

- (id)autorelease { return self; }



.单例实现:(两种方式:互斥锁(@synchronized(self))和一次性代码(dispatch_once));

//(1)重写 allocWithZone:方法,在这里创建唯一的实例(注意线程安全). //alloc 内部都会调用这个方法.

        +(instancetype)allocWithZone:(struct_NSZone *)zone {

           if(_instance ==nil) { // 防止频繁加锁

               @synchronized(self) {

                   if(_instance ==nil) { // 防止创建多次

                        _instance = [superallocWithZone:zone];

                    }

                }

            }

           return_instance;

        }

    

   //(2)重写 copyWithZone:方法.

        +(id)copyWithZone:(struct_NSZone *)zone

        {

           return_instance;

        }




NSOperation

NSInvocationOperation
NSBlockOperation
自定义子类继承 NSOperation ,实现内部相应的方法


创建 NSInvocationOperation 对象

- (id)initWithTarget:(id)targetselector:(SEL)selobject:(id)arg;

调用start 方法开始执行操作

- (void)start;


创建 NSBlockOperation 对象

+ (id)blockOperationWithBlock:(void (^)(void))block;

通过addExecutionBlock: 方法添加更多的操作

- (void)addExecutionBlock:(void (^)(void))block;




NSOperationQueue 的作用
NSOperation 可以调用start 方法来执行任务,但默认是同步执行的
如果 NSOperation 添加到 NSOperationQueue 操作队列 中, 系统会自动 异步执行 NSOperationQueue 中的 操作

添加操作到 NSOperationQueue

- (void)addOperation:(NSOperation*)op;

-( void)addOperationWithBlock:( void (^)( void))block

最大并发数的相关方法

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;


取消队列的所有操作

- (void)cancelAllOperations;

提示:也可以调用NSOperation- (void)cancel方法取消单个操作

暂停和恢复队列

- (void)setSuspended:(BOOL)b; //YES代表暂停队列,NO代表恢复队列

- (BOOL)isSuspended;


设置 NSOperation queue 中的优先级,可以改变操作的执行优先级

- (NSOperationQueuePriority)queuePriority;

- (void)setQueuePriority:(NSOperationQueuePriority)p;

优先级的取值
NSOperationQueuePriorityVeryLow = - 8L,
NSOperationQueuePriorityLow = - 4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8

可以监听一个操作的执行完毕

- (void (^)(void))completionBlock;

- (void)setCompletionBlock:(void (^)(void))block;


NSOperation 之间可以设置依赖来保证执行顺序
比如一定要让操作 A 执行完后,才能执行操作 B ,可以这么写
[operationB addDependency:operationA];





















版权声明:本文为conghailong原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。