8、多线程

  • 进程

是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位。一个进程可以包含多个线程,但至少有一个线程。进程间的内存资源是相互独立的。多开会消耗资源

  • 线程

线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
一个线程可以创建和撤销另一个线程;同一个进程中的多个线程之间可以并发执行.
多线程

  • 优点:提高程序执行效率,
  • 缺点:逻辑会比较复杂,会死锁
  • 队列

iOS中队列分为

  • 串行队列
  • 并行队列
//并发队列
dispatch_queue_t queue = dispatch_queue_create("test", DISPATCH_QUEUE_CONCURRENT)
//串行队列
dispatch_queue_create("com.hackemist.SDWebImageCache", DISPATCH_QUEUE_SERIAL);
注:队列完全使用完了之后要 release掉  dispatch_release(quequ);
  • 任务
  • 同步任务
  • 异步任务
//异步任务
    dispatch_async(quequ_chuanxing, ^{
       your Code;
    });
swift 3.0
     DispatchQueue.global().async {
     }

//同步任务
    dispatch_sync(quequ_chuanxing, ^{
        NSLog(@“异步任务”);
    });
//延时执行
    func function3() {
        let delay = DispatchTime.now() + DispatchTimeInterval.seconds(15)
        DispatchQueue.main.asyncAfter(deadline: delay) {
            self.label?.backgroundColor = UIColor.blue
            print("hhhh")
        }
    }
image.png

任务属性决定了代码是否在新线程中执行,队列决定了任务的执行顺序

| 串行队列 | 并行队列
--- | --- | ---
同步任务 | 顺序执行,阻塞主线程,不开启新线程 | 顺序执行,阻塞主线程,不开启新线程
异步任务asyns | 顺序执行,不阻塞主线程,开启新线程(里面的人都都在另一个非主线程中)| 交叉执行,不阻塞新线程,开启新线程(执行任务的每个线程都不一样)


多线程实现方式

NSThread 线程声明周期,程序猿自己管理
GCD c风格
NSOperation 面向对象,控制任务个数


dispatch_barrier_async
void dispatch_barrier_async ( dispatch_queue_t queue, dispatch_block_t block );

一个dispatch barrier 允许在一个并发队列中创建一个同步点。当在并发队列中遇到一个barrier, 他会延迟执行barrier的block,等待所有在barrier之前提交的blocks执行结束。 这时,barrier block自己开始执行。 之后, 队列继续正常的执行操作。
调用这个函数总是在barrier block被提交之后立即返回,不会等到block被执行。当barrier block到并发队列的最前端,他不会立即执行。相反,队列会等到所有当前正在执行的blocks结束执行。到这时,barrier才开始自己执行。所有在barrier block之后提交的blocks会等到barrier block结束之后才执行。
这个在globalqueue中无效,因为系统每次分配的全局队列不一定是同一个队列

线程组
dispatch_group_t serviceGroup = dispatch_group_create();//创建线程队列
dispatch_group_enter(serviceGroup);//当前任务加入队列
dispatch_group_leave(serviceGroup);//当前任务出队列

//当所有任务都出队列之后走的方法
dispatch_group_notify(serviceGroup,dispatch_get_main_queue(),^{
 });
Swift 3.0
let group = DispatchGroup.init()
group.enter()
group.leave()
group.notify(queue: DispatchQueue.main) {
     print("最终结果")
}
互斥线程锁

同一时间,只有一个线程可以访问这个资源

@synchronized(self.failedURLs) {
   isFailedUrl = [self.failedURLs containsObject:url];
}
NSOperationQueue 线程队列
 线程队列是用来存在NSOperation的容器,主要用来管理Operation,一个operation添加到Queue中一般就不再需要start了。
创建
     [[NSOperationQueuealloc]init];
方法
- (void)addOperation:(NSOperation *)op;//添加一个operation到queue中会立马异步执行

- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait NS_AVAILABLE(10_6, 4_0);//添加一组Operation到queue中,wait意思是是否阻塞当前线程,直到里面的线程执行完

- (void)addOperationWithBlock:(void (^)(void))block NS_AVAILABLE(10_6, 4_0);//直接用block创建一个operation,并添加进来

- (void)cancelAllOperations;//取消当前队列所有任务

- (void)waitUntilAllOperationsAreFinished;//阻塞当前线程,知道里面的任务全部完成

属性
      @property (readonly, copy) NSArray<__kindof NSOperation *> *operations;//当前队列中有的operation
      @property (readonly) NSUInteger operationCount NS_AVAILABLE(10_6, 4_0);//当前队列中Operation的数量
      @property NSInteger maxConcurrentOperationCount;//最大并发数量,默认没有限制
      @property (getter=isSuspended) BOOL suspended;//挂起这个队列,只能挂起还没有被执行,正在执行中的不会被暂停
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
/*告诉系统你的任务是在做什么操作
      与用户交互的任务,这些任务通常跟UI级别的刷新相关,比如动画,这些任务需要在一瞬间完成
    NSQualityOfServiceUserInitiated
    由用户发起的并且需要立即得到结果的任务,比如滑动scroll view时去加载数据用于后续cell的显示,这些任务通常跟后续的用户交互相关,在几秒或者更短的时间内完成
    NSQualityOfServiceUtility
    一些可能需要花点时间的任务,这些任务不需要马上返回结果,比如下载的任务,这些任务可能花费几秒或者几分钟的时间
    NSQualityOfServiceBackground
    这些任务对用户不可见,比如后台进行备份的操作,这些任务可能需要较长的时间,几分钟甚至几个小时
    NSQualityOfServiceDefault
    优先级介于user-initiated 和 utility,当没有 QoS信息时默认使用,开发者不应该使用这个值来设置自己的任务
*/
     @property (nullable, assign /* actually retain */) dispatch_queue_t underlyingQueue//当前queue的gcdqueue
          @property (class, readonly, strong, nullable) NSOperationQueue *currentQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
     @property (class, readonly, strong) NSOperationQueue *mainQueue NS_AVAILABLE(10_6, 4_0);//类属性,用来与其他线程间通信
NSOperation
 相当于虚类,调用start执行main方法,直接用的话啥也不干,如果使用子类的话,最好把操作写在main方法中,一般operation不加到队列里的话是在主线程执行,如果加入队列会新开线程。
 子类使用的话方法写在main中,不要写在start中,不然其他状态不会自动维护。
     - (void)start;//开始方法
     - (void)main;//开始之后执行的方法

     //取消方法与判断,当operation已经在执行中时是cancel不了的,但是会改变iscacelled的值,所以在main方法中(如sdwebimage中),才会在很多地方手动判断是否cancel,然后退出线程执行
     @property (readonly, getter=isCancelled) BOOL cancelled;
     - (void)cancel;
    //是否正在执行
@property (readonly, getter=isExecuting) BOOL executing;
//是否执行完了
@property (readonly, getter=isFinished) BOOL finished;
//是否异步,但是异步却显示0,其实默认是同步,但是加到队列,以及再加一个block会异步
@property (readonly, getter=isConcurrent) BOOL concurrent; // To be deprecated; use and override 'asynchronous' below
@property (readonly, getter=isAsynchronous) BOOL asynchronous
NS_AVAILABLE(10_8, 7_0);
//是否准备好了
@property (readonly, getter=isReady) BOOL ready;
//添加依赖,移除依赖,添加了的话就op进行完了才进行自己
- (void)addDependency:(NSOperation *)op;
- (void)removeDependency:(NSOperation *)op;
@property (readonly, copy) NSArray<NSOperation *> *dependencies;
//队列优先级
typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
};
@property NSOperationQueuePriority queuePriority;
//执行完成之后调用的block
@property (nullable, copy) void (^completionBlock)(void) NS_AVAILABLE(10_6, 4_0);
//阻塞当前线程
- (void)waitUntilFinished NS_AVAILABLE(10_6, 4_0);
//线程优先级 0 - 1
@property double threadPriority NS_DEPRECATED(10_6, 10_10, 4_0, 8_0);
//告诉系统这个线程用来干嘛
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
//名字
@property (nullable, copy) NSString *name NS_AVAILABLE(10_10, 8_0);
NSBlockOperation
+ (instancetype)blockOperationWithBlock:(void (^)(void))block;//初始化方法
 - (void)addExecutionBlock:(void (^)(void))block;//添加block会异步新开一个线程
 @property (readonly, copy) NSArray<void (^)(void)> *executionBlocks;//已经添加了的block。
NSInvocationOperation
   //初始化方法
 - (nullableinstancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullableid)arg;
 - (instancetype)initWithInvocation:(NSInvocation *)inv NS_DESIGNATED_INITIALIZER;

 @property (readonly, retain) NSInvocation *invocation;
 //返回值?
 @property (nullable, readonly, retain) id result;

两个其实相当于已经封装好了的Operation

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,826评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,968评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,234评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,562评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,611评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,482评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,271评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,166评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,608评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,814评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,926评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,644评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,249评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,866评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,991评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,063评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,871评论 2 354

推荐阅读更多精彩内容