iOS多线程浅汇-实战篇。iOS多线程。

一、前言

达到一致首稿子iOS多线程浅汇-原理篇蒙整理了片有关多线程的基本概念。本篇博文介绍的是iOS中常用的几乎单多线程技术:
NSThread
GCD
NSOperation

是因为apple不提倡开发者直接对线程进行操作,日常开支过程遭到GCD和NSOperation的运呢于多,因此NSThread会介绍得掉些,主要篇幅会在后面两个。

一、前言

二、NSThread

本篇博文介绍的凡iOS中常用的几个多线程技术:

2.1 NSThread简介

NSThread是由此apple封装的面向对象的,它同意开发者直接以面向对象的构思对线程进行操作,没一个NSThread对象就意味着一样久线程,但是开发者必须手动管理线程的生命周期,这点是apple
不提倡的。如果开发者需要手动管理线程时apple提出了以下几点建议:

1、使用GCD和NSOperation

Writing thread-creation code manually is tedious and potentially
error-prone and you should avoid it whenever possible. OS X and iOS
provide implicit support for concurrency through other APIs

合法文档中说,由于手动管理线程很平淡,并且爱出错,所以apple建议乃采取apple自家提供的GCD和NSOperation来进行多线程编程(apple心机婊,说好之手动管理线程的,怎么建议人家用你的线程自动管理API了呢)。

2、停止长日子在idle状态的线程

remember that threads consume precious system resources.Threads use a
nontrivial amount of memory, some of it wired, so releasing an idle
thread not only helps reduce your application’s memory footprint, it
also frees up more physical memory for other system processes to use

鉴于线程会占据大量之系统资源,适当的讲长时间处在挂于状态的线程停止,会自由更多之CPU和内存资源。

3、避免给多久线程同时处理一个数目

The simplest and easiest way to avoid thread-related resource
conflicts is to give each thread in your program its own copy of
whatever data it needs.
一经各国条线程都操作自己待操作的数目,如果生必不可少之说话将数据复制一份被另外一漫长线程处理。

如若您真正下定狠心要团结管理线程,让Threading Programming
Guide帮您吧。

NSThread

2.2 NSThread使用:

apple提供了简单单法子来利用NSThread:

  • 使用 detachNewThreadSelector:toTarget:withObject:

NSThread.detachNewThreadSelector(Selector("thread"), toTarget: self, withObject: nil)
  • 使用initWithTarget:selector:object:措施创建线程,但是要手动启动:

let thread = NSThread(target: self, selector:Selector("thread") , object: nil)
 thread.start()

打印结果:

2016-03-23 16:51:51.238 Mutiple[9192:3103867] NSThread-(
“<NSThread: 0x7faf50653330>{number = 3, name = (null)}”
)

  • 使用 performSelectorInBackground: withObject:艺术创建并自动启动

遗憾之是swift无法使用这法子,原因:

The performSelector: method and related selector-invoking methods are
not imported in Swift because they are inherently unsafe.

apple认为此点子无是路安全之。

GCD

2.3 NSThread几单常因此底方式:

//获取主线程和当前线程:
NSThread.mainThead()
NSThread.currentThread()

//退出,取消线程
NSThread.exit()
thread.cancel()

//判断线程状态
thread.executing//是否在运行
thread.finished   //是否结束
thread.cancelled //是否取消

//判断是否为多线程
NSThread.isMultiThread()

//使用通知根据线程状态做一些操作
NSDidBecomeSingleThreadedNotification//变为单线程
NSThreadWillExitNotification//线程即将结束
NSWillBecomeMultiThreadedNotification//即将变为多线程

//暂停线程

NSOperation

三、GCD

GCD是apple提出的吗增强多核效率的多线程实现方案,

This technology takes the thread management code you would normally
write in your own applications and moves that code down to the system
level. All you have to do is define the tasks you want to execute and
add them to an appropriate dispatch queue. GCD takes care of creating
the needed threads and of scheduling your tasks to run on those
threads

她当系层级帮助开发者维护线程的生命周期,包括线程的创造、休眠、销毁等,开发者只需要关怀需要实现的效力,将需开的操作放到调度班(dispatch
queue)中,系统会冲线程的景况自行分配资源。

GCD引入了职责(task)和调度班(dispatch queue)的定义。
所谓的天职,其实就是是你如果促成的法力以及操作,即你要是召开什么;
调度班,是贯彻效益的办法,简单说即使是你想怎么开。

apple列举了dispatch queue的博独到之处:

  • 供了还简洁之落实多线程的接口,让代码更简明
  • 扶开发者管理线程的生命周期
  • 异步队列中未见面导致死锁

排中的装有任务还以FIFO的一一执行,GCD提供了三种阵:

  • 差行队列
  • 相互之间队列
  • 主队列

鉴于apple不提倡开发者直接对线程进行操作,日常开支过程遭到GCD和NSOperation的运用与否于多,因此NSThread会介绍得少几,主要篇幅会在后面两只。

3.1差行队列

  • 创建
    使用dispatch_queue_create(label: UnsafePointer<Int8>, attr: dispatch_queue_attr_t)措施创建行,来看望apple对法中的少单特性的说:

label:
A string label to attach to the queue to uniquely identify it in
debugging tools such as Instruments, sample, stackshots, and crash
reports. Because applications, libraries, and frameworks can all
create their own dispatch queues, a reverse-DNS naming style
(com.example.myqueue) is recommended. This parameter is optional and
can be NULL.

label是行的名目,apple推荐使用com.example.myQueue的条条框框来定名队列,用于debug的时刻追踪队列以便于调试,可以啊空

attr:
In OS X v10.7 and later or iOS 4.3 and later, specify
DISPATCH_QUEUE_SERIAL (or NULL) to create a serial queue or specify
DISPATCH_QUEUE_CONCURRENT to create a concurrent queue. In earlier
versions, you must specify NULL for this parameter.

attr用于指定是串行队列还是并行队列,如果是NULL则默认串行队列

let serialQ1 = dispatch_queue_create("com.hah.serialQ1",DISPATCH_QUEUE_SERIAL)

或者

let serialQ2 = dispatch_queue_create("com.hah.serialQ2")

差行队列中之天职会按照FIFO的逐一依次执行,在一块儿实施下,系统不会见被新的线程,默认在主线程下执行任务,如果是以异步执行下,系统会冲线程资源情况决定是否被新的线程。

GCD中得以经过串行队列进行锁线程

来瞧同步情况下任务的尽情况:

  • 合串行:任务一个随着一个实行,不起头起新线程;

        func syncSerial() {
          NSLog("=======>>>syncSerial<<<========")
          let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)
    
          dispatch_sync(q1) { () -> Void in
              NSLog("1-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("2-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("3-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("4-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("5-%@",NSThread.currentThread()]);
          }
          NSLog("=======>>>syncSerial<<<========")
      }
    

    打印结果:

2016-03-23 13:38:29.521 Mutiple[8199:2165063]
=======>>>syncSerial<<<========
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 1-(
“<NSThread: 0x7f8418502320>{number = 1, name = main}”
)
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 2-(
“<NSThread: 0x7f8418502320>{number = 1, name = main}”
)
2016-03-23 13:38:29.522 Mutiple[8199:2165063] 3-(
“<NSThread: 0x7f8418502320>{number = 1, name = main}”
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063] 4-(
“<NSThread: 0x7f8418502320>{number = 1, name = main}”
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063] 5-(
“<NSThread: 0x7f8418502320>{number = 1, name = main}”
)
2016-03-23 13:38:29.523 Mutiple[8199:2165063]
=======>>>syncSerial<<<========

  • 异步串行:任务一个随后一个执行,系统基于线程资源状况决定是否被新的线程;

        func asyncSerail() {
          NSLog("=======>>>asyncSerail<<<========")
          let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)
    
          dispatch_async(q1) { () -> Void in
              NSLog("1-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("2-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("3-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("4-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("5-%@",NSThread.currentThread());
          }
          NSLog("=======>>>asyncSerail<<<========")
      }
    

打印结果:

2016-03-23 13:04:26.713 Mutiple[7294:1959223]
=======>>>asyncSerail<<<========
2016-03-23 13:04:26.714 Mutiple[7294:1959223]
=======>>>asyncSerail<<<========
2016-03-23 13:04:26.715 Mutiple[7294:1959473] 1-(
“<NSThread: 0x7faebac3c740>{number = 3, name = (null)}”
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 2-(
“<NSThread: 0x7faebac3c740>{number = 3, name = (null)}”
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 3-(
“<NSThread: 0x7faebac3c740>{number = 3, name = (null)}”
)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 4-(

"<NSThread: 0x7faebac3c740>{number = 3, name = (null)}"

)
2016-03-23 13:04:26.716 Mutiple[7294:1959473] 5-(
“<NSThread: 0x7faebac3c740>{number = 3, name = (null)}”
)

自打印好看来,系统被了新的线程,但是所有的职责都是以跟一个线程里形成,避免在多只线程之间切换。

二、NSThread

3.2 并履行队列

相队列,是全局队列的一样栽,它能处理并发任务。apple提供了季独既创办好之交互队列,又被全局队列(global
queu),开发者只需要调用dispatch_get_global_queue( , )就会取一个互动队列。并行队列同样仍FIFO的口径执行任务,它同意多只任务并实施,同时实行的职责数系统会根据事态控制。iOS5后头,apple也允许开发者自己创立并行队列。

2.1 NSThread简介

3.2.1 获取全局队列:

调用dispatch_get_global_queue(identifier: Int, flags: UInt)术获得全局队列:
些微个参数:

identifier:
The quality of service you want to give to tasks executed using this
queue. Quality-of-service helps determine the priority given to tasks
executed by the queue. Queues that handle user-interactive or
user-initiated tasks have a higher priority than tasks meant to run in
the background.

identifier用于指定全局队列的优先级,有4种档次:

#define DISPATCH_QUEUE_PRIORITY_HIGH        2
#define DISPATCH_QUEUE_PRIORITY_DEFAULT     0
#define DISPATCH_QUEUE_PRIORITY_LOW         (-2)
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND  INT16_MIN

iOS 8以后好经:

QOS_CLASS_USER_INTERACTIVE,
QOS_CLASS_USER_INITIATED, 
QOS_CLASS_UTILITY
QOS_CLASS_BACKGROUND.

来安优先级。

自字面上虽能够顾,优先级的轻重顺序吧:DISPATCH_QUEUE_PRIORITY_HIGH>DISPATCH_QUEUE_PRIORITY_DEFAULT>DISPATCH_QUEUE_PRIORITY_LOW>DISPATCH_QUEUE_PRIORITY_BACKGROUND
得特地说一下之是,系统建议用关于磁盘的I/0操作放到DISPATCH_QUEUE_PRIORITY_BACKGROUND先行级的阵中,防止占过多的系统资源。

flags :
Flags that are reserved for future use. Always specify 0 for this
parameter.

flag默认是0

let highQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)

//默认优先级也可以这么写:let defaultQ = dispatch_get_global_queue(0, 0)
let defaultQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

let lowQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0)

let bgQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)

自勾勒了段代码模拟了下优先级赛之行先实施的情事:

    func queuePriority() {
        let highQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)
        let defaultQ = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)

        dispatch_async(defaultQ) { () -> Void in
            NSLog("task3 start-%@",NSThread.currentThread());
        }

        dispatch_async(highQ) { () -> Void in
            NSLog("task1 start-%@",NSThread.currentThread());
        }
    }

按理说,应该是事先实行task1,因为它预先级比较大,但是log是这么的:

2016-03-24 16:12:49.308 Mutiple[3815:2019744] task3 start-(
“<NSThread: 0x14de16b40>{number = 3, name = (null)}”
)
2016-03-24 16:12:49.308 Mutiple[3815:2019743] task1 start-(
“<NSThread: 0x14dd4e7b0>{number = 4, name = (null)}”
)

预先级赛之未事先实施了,why?
自家于是事先级high和low做了尝试,发现high优先级总是先实施,但是default为什么就杀啊?这个小还免亮。

NSThread是经过apple封装的面向对象的,它同意开发者直接盖面向对象的沉思对线程进行操作,没一个NSThread对象就是象征一如既往长条线程,但是开发者必须手动管理线程的生命周期,这点是apple
不提倡的。如果开发者需要手动管理线程时apple提出了以下几点建议:

3.2.2 手动创建并行队列

紧接下手动创建一个彼此队列,查看线程的缔造情况:

  • 共并行:任务一个接着一个尽,系统默认不上马起新线程;

        func syncConcurrency() {
          NSLog("=======>>>syncConcurrency<<<========")
          let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_CONCURRENT)
    
          dispatch_sync(q1) { () -> Void in
              NSLog("1-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("2-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("3-%@",[NSThread .currentThread()]);
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("4-%@",NSThread.currentThread());
          }
    
          dispatch_sync(q1) { () -> Void in
              NSLog("5-%@",NSThread.currentThread());
          }
          NSLog("=======>>>syncConcurrency<<<========")
      }
    

打印结果:

2016-03-23 13:40:16.968 Mutiple[8256:2181632]
=======>>>syncConcurrency<<<========
2016-03-23 13:40:16.969 Mutiple[8256:2181632] 1-(
“<NSThread: 0x7fad99605d70>{number = 1, name = main}”
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 2-(
“<NSThread: 0x7fad99605d70>{number = 1, name = main}”
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 3-(
“<NSThread: 0x7fad99605d70>{number = 1, name = main}”
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 4-(
“<NSThread: 0x7fad99605d70>{number = 1, name = main}”
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632] 5-(
“<NSThread: 0x7fad99605d70>{number = 1, name = main}”
)
2016-03-23 13:40:16.970 Mutiple[8256:2181632]
=======>>>syncConcurrency<<<========

打打印输出可以观看,所有任务都是以主线程遭遇好,因为一起实施,即使开了多只线程,下一个之天职还是如待当前任务执行了才会开施行,开多单线程之后导致资源浪费。就如iOS多线程浅汇-原理篇惨遭说到之,如果这时段起了三长达线程,系统就非得于三长长的线程之间切换,除此之外,每条线程都发好的栈和寄存器,三长线程就出三组的栈和寄存器被复制和替换,这相对于单纯发雷同漫漫线程来说,效率必然是大大降低的。

  • 异步并行:多独任务并实施,顺序不固定,但是好透过dispatch_group和NSOperation添加借助控制任务尽各个。

        func asyncConcurrency() {
          NSLog("=======>>>asyncConcurrency<<<========")
          let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_CONCURRENT)
    
          dispatch_async(q1) { () -> Void in
              NSLog("1-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("2-%@",NSThread.currentThread();
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("3-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("4-%@",NSThread.currentThread());
          }
    
          dispatch_async(q1) { () -> Void in
              NSLog("5-%@",NSThread.currentThread());
          }
          NSLog("=======>>>asyncConcurrency<<<========")
      }
    

打印结果:

2016-03-23 13:30:20.987 Mutiple[8107:2109033]
=======>>>asyncConcurrency<<<========
2016-03-23 13:30:20.988 Mutiple[8107:2109033]
=======>>>asyncConcurrency<<<========
2016-03-23 13:30:20.989 Mutiple[8107:2109139] 5-(
“<NSThread: 0x7fcca2546420>{number = 7, name = (null)}”
)
2016-03-23 13:30:20.989 Mutiple[8107:2109119] 3-(
“<NSThread: 0x7fcca2733150>{number = 4, name = (null)}”
)
2016-03-23 13:30:20.989 Mutiple[8107:2109093] 1-(
“<NSThread: 0x7fcca2732c90>{number = 3, name = (null)}”

)
2016-03-23 13:30:20.989 Mutiple[8107:2109118] 2-(
“<NSThread: 0x7fcca253ea80>{number = 5, name = (null)}”
)
2016-03-23 13:30:20.990 Mutiple[8107:2109138] 4-(
“<NSThread: 0x7fcca263a5e0>{number = 6, name = (null)}”
)

  • 异步下开创多独串行队列实现相互之间效果

      func multiAsyncSerail() {
          NSLog("=======>>>asyncSerail<<<========")
          let q1 = dispatch_queue_create("q1",DISPATCH_QUEUE_SERIAL)
    
          dispatch_async(q1) { () -> Void in
              NSLog("1-%@",NSThread.currentThread());
          }
    
                  let q2 = dispatch_queue_create("q2",DISPATCH_QUEUE_SERIAL)
          dispatch_async(q2) { () -> Void in
              NSLog("2-%@",NSThread.currentThread());
          }
    
                  let q3 = dispatch_queue_create("q3",DISPATCH_QUEUE_SERIAL)
          dispatch_async(q3) { () -> Void in
              NSLog("3-%@",NSThread.currentThread());
          }
    
                  let q4 = dispatch_queue_create("q4",DISPATCH_QUEUE_SERIAL)
          dispatch_async(q4) { () -> Void in
              NSLog("4-%@",NSThread.currentThread());
          }
    
          let q5 = dispatch_queue_create("q5",DISPATCH_QUEUE_SERIAL)
          dispatch_async(q5) { () -> Void in
              NSLog("5-%@",NSThread.currentThread());
          }
          NSLog("=======>>>asyncSerail<<<========")
      }
    

打印结果:

2016-03-23 13:33:21.412 Mutiple[8150:2128078]
=======>>>asyncSerail<<<========
2016-03-23 13:33:21.413 Mutiple[8150:2128078]
=======>>>asyncSerail<<<========
2016-03-23 13:33:21.414 Mutiple[8150:2128320] 4-(

"<NSThread: 0x7fa520413420>{number = 7, name = (null)}"

)
2016-03-23 13:33:21.414 Mutiple[8150:2128308] 1-(
“<NSThread: 0x7fa52044b4d0>{number = 3, name = (null)}”
)
2016-03-23 13:33:21.414 Mutiple[8150:2128312] 3-(
“<NSThread: 0x7fa520432f10>{number = 5, name = (null)}”
)
2016-03-23 13:33:21.414 Mutiple[8150:2128321] 5-(
“<NSThread: 0x7fa52040beb0>{number = 6, name = (null)}”
)
2016-03-23 13:33:21.414 Mutiple[8150:2128311] 2-(
“<NSThread: 0x7fa52061ff60>{number = 4, name = (null)}”
)

1、使用GCD和NSOperation

小结:

运用GCD实现多线程时:

  • 共同串行和合并行:都见面以顺序依次执行任务,且不见面开新的线程。

  • 异步串行:会被新的线程,但是系统默认在同一线程内以职责逐一依次执行,因为这时段起了多独线程也使挨个执行任务,开线程只会造成资源浪费

  • 异步并行:开启多只线程,有多独任务而施行,系统会因各国条线程的状分配,执行顺序不固定。

  • 于异步串行情况下,可以经过创建多个串行队列,实现异步并行的力量,让大多单任务而开展。

Writing thread-creation code manually is tedious and potentially
error-prone and you should avoid it whenever possible. OS X and iOS
provide implicit support for concurrency through other APIs

3.3 主队列

The main dispatch queue is a globally available serial queue that
executes tasks on the application’s main thread.

主队列是一个全局性的串行队列,用于执行app中主线程的职责,对run
loop起作用,将配属于run
loop的轩然大波源于及队列任务之实施交织在联合(官方文档翻译过来的,太生硬了。。。)。主队列是一个于app来说很重中之重之同步点,凡是与UI和用户举报有关的且不能不付出主队列好。这个队列是系活动创建的,开发者只需要取得队列,并尽操作即可。

抱主线程的法子:

let mainQueue = dispatch_get_main_queue()

最为常用底:

let queue = dispatch_get_global_queue(0,0)
dispatch_async(queue,{ () -> Void in
   //在这里做一些耗时的操作
   dispatch_async(dispatch_get_main_queue(),{ () -> Void in
       //刷新UI
   })
})

法定文档中说,由于手动管理线程很平淡,并且爱失误,所以apple建议您下apple自家提供的GCD和NSOperation来展开多线程编程(apple心机婊,说好的手动管理线程的,怎么建议人家用你的线程自动管理API了啊)。

3.4 队列组(dispatch group)

Dispatch groups are a way to block a thread until one or more tasks
finish executing.Groups provide a useful synchronization mechanism for
code that depends on the completion of other tasks

使用队列组能够落实叫一个还是多独任务执行完毕之后再也实践下一个任务。

Another way to use dispatch groups is as an alternative to thread
joins.

使用队列组将多单任务连续于协同。

从而起列组可以当一定的景下促成有一定的成效,十分妙不可言:

加盟有三独任务:taks1,task2,taks3。task1与task2没有呀异样关系,task3亟待等task1和task2结束以后才会起执行。

  • 使用队列组实现任务等待

    func dispatchGroup() {
        let group = dispatch_group_create()
        let queue1 = dispatch_get_global_queue(0, 0)
        let queue2 = dispatch_get_global_queue(0, 0)
        let queue3 = dispatch_get_global_queue(0, 0)

        dispatch_group_async(group, queue1) { () -> Void in
            for i in 0..<3 {
                NSLog("task1 - %d",i)
            }
        }

        dispatch_group_async(group, queue2) { () -> Void in
            for i in 0..<3 {
                NSLog("task2 - %d",i)
            }
        }

        dispatch_group_wait(group, DISPATCH_TIME_FOREVER)

        NSLog("wait completed")

        dispatch_group_async(group, queue3) { () -> Void in
            for i in 0..<3 {
                NSLog("task3 - %d",i)
            }
        }
    }

log输出:

2016-03-24 22:23:25.717 2016-03-24 22:42:42.465
MultipleThradDemo[49112:4109966] task2 – 0
2016-03-24 22:42:42.465 MultipleThradDemo[49112:4109967] task1 – 0
2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109966] task2 – 1
2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109967] task1 – 1
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109966] task2 – 2
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109967] task1 – 2
2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109901] wait
completed
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 0
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 1
2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 2

dispatch_group_wait(group: dispatch_group_t, timeout:dispatch_time_t):括号中的首先单参数group否等候的行组,第二只timeout也等待的时空

  • 应用队列组的通报功能实现上述情景:

   func groupNotify() {
       let group = dispatch_group_create()
       let queue1 = dispatch_get_global_queue(0, 0)
       let queue2 = dispatch_get_global_queue(0, 0)
       let queue3 = dispatch_get_global_queue(0, 0)

       dispatch_group_async(group, queue1) { () -> Void in
           for i in 0..<3 {
               NSLog("task1 - %d",i)
           }
       }

       dispatch_group_async(group, queue2) { () -> Void in
           for i in 0..<3 {
               NSLog("task2 - %d",i)
           }
       }

       dispatch_group_notify(group, queue3) { () -> Void in
           NSLog("task1、 task2 completed")
           for i in 0..<3 {
               NSLog("task3 - %d",i)
           }
       }
   }

log输出:

2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127151] task2 – 0
2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127148] task1 – 0
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 – 1
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 – 1
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 – 2
2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 – 2
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task1、
task2 completed
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 0

2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 1
2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 2

2、停止长时以idle状态的线程

3.5 GCD的线程安全

尽管GCD本身就是是线程安全之,但是为了更好之用GCD,apple还是吃了几乎独建议:

Do not call the dispatch_sync function from a task that is executing
on the same queue that you pass to your function call

以本队列调用dispatch_sync,再以按照队列传入同步方法会导致死锁。

我眷恋apple 的意应该是这般的:

    func deadLock() {
    //let q = dispatch_get_global_queue(0, 0)
        let q = dispatch_queue_create("come.multiThread.serialQ", DISPATCH_QUEUE_SERIAL)

        dispatch_async(q) { () -> Void in
            NSLog("1 start-%@",[NSThread .currentThread()]);
            dispatch_sync(q, { () -> Void in
                NSLog("2 start-%@",[NSThread .currentThread()]);
            })
            NSLog("3 start-%@",[NSThread .currentThread()]);
        }
        NSLog("4 start-%@",[NSThread .currentThread()]);
    }

只是自己发现会无会见造成死锁和眼前班是串行还是并行有关。
一旦是串行队列,同步执行会阻塞线程,而且串行队列一软只能实行一个职责,q里面等待的天职以及协办阻塞的任务是同一个职责,造成死锁。
假若是互队列,一不好克实施多个任务,即使一同阻塞了线程,由于足基本上只任务并实施,q里面没有任务等,不见面招死锁。

stackoverflow上看似问题之答疑:

Using dispatch_sync() to enqueue a Block to the serial queue on
which you’re already running is guaranteed to deadlock.Using
dispatch_sync() to enqueue a Block to the concurrent queue on
which you’re already running is quite likely to deadlock.

派发同步任务到于正推行之串行队列肯定会招致死锁;派发到彼此队列也发深死的或是导致死锁。所以地方的例证中,并推行队列虽然尚未导致死锁,还是生风险的。

note:往主线程派发同任务也会造成死锁

    func mainThreadLock() {
        let main = dispatch_get_main_queue()
        NSLog("start-%@",[NSThread .currentThread()]);
        dispatch_sync(main) { () -> Void in
            NSLog("1 -%@",[NSThread .currentThread()]);
        }
        NSLog("end-%@",[NSThread .currentThread()]);
    }

打印输出:

2016-03-25 10:15:46.638 Mutiple[15813:5558093] start-(
“<NSThread: 0x7fae226029d0>{number = 1, name = main}”
)

联手任务以及主线程任务相互等待,造成死锁。

Avoid taking locks from the tasks you submit to a dispatch queue.If
you need to synchronize parts of your code, use a serial dispatch
queue instead of a lock.

尽量不用好锁线程,否则得到的结果可能会见死压倒你的预料。使用GCD实现多线程时,apple建议就此串行队列替代线程锁。

remember that threads consume precious system resources.Threads use a
nontrivial amount of memory, some of it wired, so releasing an idle
thread not only helps reduce your application’s memory footprint, it
also frees up more physical memory for other system processes to use

3.6 GCD的其余常用方法

是因为线程会占据大量之系统资源,适当的讲长时间处在挂于状态的线程停止,会放更多之CPU和内存资源。

3.6.1 dispatch_group_enter

dispatch_group_enter()dispatch_group_leave()举凡用于进入group和离group的指令方法,是用来手动管理group的block块的措施,下面两段子代码的成效是同样的:

let group = dispatch_group_create()
let queue = dispatch_get_global_queue(0,0)
//实现异步操作
dispatch_group_enter(group)
dispatch_async(queue,^{
    //异步操作
    dispatch_group_leave(group)
})

//等价于
dispatch_group_async(group,queue,^{
    //异步操作
})

3、避免让大多漫漫线程同时处理一个数额

3.6.1 dispatch semaphore

dispatch semaphore
信号量用于控制以做客与一个资源的职责数。当一个并行任务中待对资源数量做还粗部分的支配或多单线程存在竞争之时节,信号量就换得稀行。
信号量主要出三个点子:

/*!
  *@function
  *创建信号量
  *
  *@description
  *value=0:两个线程需要同时完成
  *value<0:返回NULL
  *
  *@param value
  *用于指定开始的时候的信号量的个数
 */
func dispatch_semaphore_create(value:Int) -> dispatch_semaphore_t!

/*!
  *@function
  *等待信号,并使得create方法中的value值-1
  *
  *@description
  *返回值>=0时使得信号量减一并继续执行以下代码,<0会等待信号量发送后再返回返回值
  *
  *@param dsema
  *等待的信号
  *
  *@param timeout
  *等待的时间
  *@result
  *0:成功,非零:等待
 */
func dispatch_semaphore_wait(dsema: dispatch_semaphore_t,timeout: dispatch_time_t) -> Int

/*!
  *@function
  *使得信号量增加
  *
  *@description
  *如果要返回的值<0,会先唤醒一个等待线程再返回值
  *
  *@param dsema
  *等待的信号
  *
  *@result
  *0:未能唤醒线程,非零:唤醒线程
 */
func dispatch_semaphore_signal(dsema:dispatch_semaphore_t) -> Int

圈一个事例:

func changeMutableArray() {
    var arr = [Int]()
    let queue1 = dispatch_get_global_queue(0, 0)

    for i in 0...3 {
        dispatch_async(queue1) { () -> Void in
            NSLog("task2 - %d",i)
            arr.append(i)
            NSLog("\(arr)")
        }
    }
}

于个别独异步线程中对一个可变数组开补偿加元素操作,由于可变数组不支持多线程操作,当半独线程同时做客它时即便会见招致数据错乱,我得出了这样的打印:

2016-03-28 16:44:34.193 Mutiple[5669:1717543] task2 – 1
2016-03-28 16:44:34.193 Mutiple[5669:1717545] task2 – 2
2016-03-28 16:44:34.193 Mutiple[5669:1717544] task2 – 0
2016-03-28 16:44:34.193 Mutiple[5669:1717554] task2 – 3
2016-03-28 16:44:34.194 Mutiple[5669:1717544] [1, 2, 0]
2016-03-28 16:44:34.194 Mutiple[5669:1717554] [1, 2, 0, 3]
2016-03-28 16:44:34.194 Mutiple[5669:1717545] [1, 2, 0]
2016-03-28 16:44:34.194 Mutiple[5669:1717543] [1, 2]

加上了信号量的护卫后,代码是如此的

func changeMutableArray() {
    var arr = [Int]()
    let queue1 = dispatch_get_global_queue(0, 0)

    let semaphore = dispatch_semaphore_create(1)

    for i in 0...3 {
        dispatch_async(queue1) { () -> Void in

            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

            NSLog("task2 - %d",i)
            arr.append(i)
            NSLog("\(arr)")

            dispatch_semaphore_signal(semaphore)
        }
    }
}

正巧开创造的时定义了始于的计数器的价为1,dispatch_semaphore_wait()每当尽前见面优先判断时之counter值,如果counter值大于等于1,会朝着生实施代码,并且令counter值减1,如果counter的价值仅次于1,等待dispatch_semaphore_signal()方式执行,该方式会令counter加1,当counter大于等于1
wait措施才会继续执行以下的代码,

打印出来的log 信息是这般的:

2016-03-28 16:46:54.272 Mutiple[5697:1733417] task2 – 0
2016-03-28 16:46:54.273 Mutiple[5697:1733417] [0]
2016-03-28 16:46:54.273 Mutiple[5697:1733416] task2 – 1
2016-03-28 16:46:54.273 Mutiple[5697:1733416] [0, 1]
2016-03-28 16:46:54.274 Mutiple[5697:1733440] task2 – 2
2016-03-28 16:46:54.274 Mutiple[5697:1733440] [0, 1, 2]
2016-03-28 16:46:54.274 Mutiple[5697:1733463] task2 – 3
2016-03-28 16:46:54.274 Mutiple[5697:1733463] [0, 1, 2, 3]

足见见,信号量在竞争上加下保证了望数组上加元素的安全性。

除信号量还足以这么用

let result = dispatch_semaphore_wait(dsema,DISPATCH_TIME_FORVEER)
if result > 0 {
    //做异步操作
}else{
    //等待signal方法增加counter值
}

NOTE:如果wait和signal不匹配出现可能会见崩溃。

The simplest and easiest way to avoid thread-related resource conflicts
is to give each thread in your program its own copy of whatever data it
needs.

3.6.2 dispatch barrier

dispatch
barrier允许开发者在一个互相队列中创造一个同步点,其实为是用来在竞争条件下资源的保护,防止同一资源而为使用。在互相队列中,barrier中之代码会等到该队列的有所并行条件了后才会单独实施barrier。

barrier两单常因此智:

/*
 *@discussion
 *将barrier代码块提交到队列中,然后马上返回。
 *等待队列执行完barrier前面的所有代码之后,barrier里面的代码会单独执行,
 *等到barrier代码执行完毕,队列继续往下执行。
 */
func dispatch_barrier_async(queu: dispatch_queue_t, block: dispatch_block_t)

note:这个队应该运用好创造的班,如果传入的凡一个串行队列或者全局队列,那么这个点子与dsipatch_async的功用是一样的。

/*
 *@discussion
 *提交barrier到队列,等待barrier的block执行完毕再返回。
 *这个方法会等待block执行完毕才会返回。
 *同dispatch_barrier_async,队列需要使用自己创建的私人队列。
 */
func dispatch_barrier_sync(queue:dispatch_queue_t, block: dispatch_block_t)
```

**note: 在当前队列中调用此方法会造成死锁, 系统倾向于当前线程中(而不是再开一条线程)调用此方法使性能最优。**

`dispatch_barrier_async`传入自己创建的并行队列时,会阻塞**当前队列**执行,而不阻塞当前线程。
`dispatch_barrier_sync `传入自己创建的并行队列时,会阻塞当前线程,所有在正在执行的队列中调用次方法会使队列任务相互等待,造成死锁。

用代码试验一下:
```
func asyncBarrier() {
    let queue = dispatch_queue_create("com.multiThread.barrierQ", DISPATCH_QUEUE_CONCURRENT)

    dispatch_async(queue) { () -> Void in
        for i in 0...2 {
            NSLog("task1 - %d",i)
        }
    }

    dispatch_barrier_async(queue) { () -> Void in
        NSLog("=====>>>barrier1 start <<<======")
        for i in 0...2 {
            NSLog("task2 - %d",i)
        }
        NSLog("=====>>>barrier1 completed <<<======")
    }

    dispatch_async(queue) { () -> Void in
        for i in 0...2 {
            NSLog("task4 - %d",i)
        }
    }
}
```

打印输出:
>2016-03-29 11:11:33.496 Mutiple[7756:2543177] task1 - 0
2016-03-29 11:11:33.496 Mutiple[7756:2543177] task1 - 1
2016-03-29 11:11:33.496 Mutiple[7756:2543177] task1 - 2
2016-03-29 11:11:33.497 Mutiple[7756:2543177] =====>>>barrier1 start <<<======
2016-03-29 11:11:33.497 Mutiple[7756:2543177] task2 - 0
2016-03-29 11:11:33.497 Mutiple[7756:2543177] task2 - 1
2016-03-29 11:11:33.497 Mutiple[7756:2543177] task2 - 2
2016-03-29 11:11:33.497 Mutiple[7756:2543177] =====>>>barrier1 completed <<<======
2016-03-29 11:11:33.497 Mutiple[7756:2543177] task4 - 0
2016-03-29 11:11:33.497 Mutiple[7756:2543177] task4 - 1
2016-03-29 11:11:33.498 Mutiple[7756:2543177] task4 - 2

造成死锁的情况:
```
func syncBarrier() {
    let queue = dispatch_queue_create("com.multiThread.barrierQ", DISPATCH_QUEUE_CONCURRENT)
    dispatch_async(queue) { () -> Void in
        NSLog("sync barrier start")
        dispatch_barrier_sync(queue) { () -> Void in
            NSLog("=====>>>barrier1 start <<<======")
            for i in 0...2 {
                NSLog("task2 - %d",i)
            }
            NSLog("=====>>>barrier1 completed <<<======")
        }
        NSLog("sync barrier completed")
    }
}
```

只有一条打印信息:
>2016-03-29 11:15:03.510 Mutiple[7851:2563610] sync barrier start

####3.6.3 dispatch source
dispatch source是一个监视某些类型事件的对象。当这些事件发生时,它自动将一个block放入一个dispatch queue的执行例程中。
GCD支持以下的dispatch source类型:
* *Timer dispatch sources*
* *Signal dispatch sources*
* *Descriptor sources* 
* *Process dispatch sources* 
* *Mach port dispatch sources* 
* *Custom dispatch sources* 

dispatch sources 用一些异步回调方法处理系统相关的事件。不像之前手动的将任务提交到dispatch queue,dispatch source为app提供了持续的事件源,在你取消它之前它都会一直连接这dispatch queue,等待着事件的触发(有点像通知的感觉)

* 创建source
```
//dispatch source 一直处于挂起状态,创建source,配置了handler和context之后,需要调用dispatch_resume()方法
public func dispatch_source_create(type: dispatch_source_type_t, 
                                 _ handle: UInt, _ mask: Uint,
                                  _ queue: dispatch_queue_t!) -> dispatch_source_t!
```

* 配置事件
```
dispatch_source_set_event_handle(source:dispatch_source_t, handler: dispatch_block_t!)
```

文档中的示例代码:
```
dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
                                 myDescriptor, 0, myQueue);
dispatch_source_set_event_handler(source, ^{
   // Get some data from the source variable, which is captured
   // from the parent context.
   size_t estimated = dispatch_source_get_data(source);

   // Continue reading the descriptor...
});
dispatch_resume(source);
```

##四、NSOeration
NSOperation 是apple 提供的面向对象的多线程实现方案。`NSOperation`和`NSOperationQueue`分别对应GCD中的task和queue

`NSOperation`是一个抽象类,不能直接创建对象封装任务,可以使用它的两个子类`NSInvocationOperation`和`NSBlockOperation`或者自己创建继承自NSOperation的类对象封装任务。

###4.1 NSInvocation的使用:
```
NSInvocation *invocation = [[NSInvocation alloc] initWithTarget:aTarget 
                                                       selector:@selector(aSelector) 
                                                         object:nil];
[invocation start];
```

*NOTE:Swift中认为`NSInvocationOperation`是非类型安全的,所有不能使用*

###4.2 NSBlockOperation
NSBlockOperation可以并行执行一个或多个任务,开发者只需要将任务放到block里面。在创建NSBlockOperation对象的时候,你就要应该初始化至少一个block。这个operation会等到所有的block都执行完毕才会结束。`finished`属性是一个布尔值,可以监测blockOperation是否执行完毕。将一组的任务添加到block,然后监测`finished`就能追踪一组任务的完成情况。

基本用法
```
func blockOperation() {

    let theOP = NSBlockOperation { () -> Void in
        for i in 0...2 {
            NSLog("task1 - %d",i)
        }
    }
    theOP.addExecutionBlock { () -> Void in
        for i in 0...2 {
            NSLog("task2 - %d",i)
        }
    }
    //不调用start方法不会开始执行
    theOP.start()
}
```

###4.3 自定义operation子类
当系统提供的两个NSOperation的子类无法满足咱们的需求的时候,咱们就要创建继承自NSOperation的对象来实现更多更复杂的操作。
自己创建的子类对象必要实现两个方法:
* 自定义的初始化方法
* 重写`main`方法。在这个方法里面所需要的操作,一般会建立自己的自动释放池,原因:异步执行的时候无法访问主线程的释放池,不会及时释放,可能造成资源浪费

```
@interface MyNonConcurrentOperation : NSOperation
@property (strong) id myData;
-(id)initWithData:(id)data;
@end

@implementation MyNonConcurrentOperation
- (id)initWithData:(id)data {
   if (self = [super init])
      myData = data;
   return self;
}

-(void)main {
    @autoreleasepool{
        //执行操作
    }
}
@end
```

###4.4 让NSOperation实现并行的几个方法
operation对象默认以同步方式执行任务,哪条线程调用了start方法,就会在哪条线程上执行任务。尽管大多数operation是异步运行的,operation队列只提供非并行操作的线程。如果开发者要实现真正的并行操作,可以通过重写以下几个方法:
* start(Required)
所有的并发操作都必须重写这个方法,用自己的实现方式替代默认的。执行操作时,调用`start`方法,作为执行任务的起始点,在任何时候都不应该调用 `super`的`start`方法

* main(Optional)
主要用于实现与operation对象相关的操作,尽管你可以在`start`方法中执行任务,但是将执行任务的代码放到这个方法中,会使得配置代码与任务代码分离得更加清晰些。

* isExcuting & isFinished(Required)
用于向外部报告任务的执行情况,实现这两个方法时需要保证线程安全。

* isConcurrent(Required)
标记一个operation是否是并行操作,只需要重写这个方法 返回`YES`。

简单实现功能:
```
@interface MyOperation : NSOperation {
    BOOL        executing;
    BOOL        finished;
}
- (void)completeOperation;
@end

@implementation MyOperation
- (id)init {
    self = [super init];
    if (self) {
        executing = NO;
        finished = NO;
    }
    return self;
}

- (void)start {
   // Always check for cancellation before launching the task.
   if ([self isCancelled])
   {
      // Must move the operation to the finished state if it is canceled.
      [self willChangeValueForKey:@"isFinished"];
      finished = YES;
      [self didChangeValueForKey:@"isFinished"];
      return;
   }

   // If the operation is not canceled, begin executing the task.
   [self willChangeValueForKey:@"isExecuting"];
   [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
   executing = YES;
   [self didChangeValueForKey:@"isExecuting"];
}

- (void)main {
   @autoreleasepool {
       [self completeOperation];
   }
}

- (void)completeOperation {
    [self willChangeValueForKey:@"isFinished"];
    [self willChangeValueForKey:@"isExecuting"];

    executing = NO;
    finished = YES;

    [self didChangeValueForKey:@"isExecuting"];
    [self didChangeValueForKey:@"isFinished"];
}

- (BOOL)isConcurrent {
    return YES;
}

- (BOOL)isExecuting {
    return executing;
}

- (BOOL)isFinished {
    return finished;
}
@end
```

###4.5 NSOpreationQueue
同GCD种的dispatch queue一样,operation queue由系统控制,开发者只需要把任务提交给它,系统会自动判断决定同时运行的操作个数,多创建一个queue并不意味着你可以同时执行更多的操作。
```
//创建一个operation queue
let OPQueue = NSOperationQueue()

//添加操作
[aQueue addOperation:anOp]; // Add a single operation
//添加操作组,并决定是否等待组内操作完成再继续往下执行
[aQueue addOperations:anArrayOfOps waitUntilFinished:NO]; // Add multiple operations
//直接添加操作到block中
[aQueue addOperationWithBlock:^{
   /* Do something. */
}];
```

> **Important**: *Never modify an operation object after it has been added to a queue. While waiting in a queue, the operation could start executing at any time, so changing its dependencies or the data it contains could have adverse effects. If you want to know the status of an operation, you can use the methods of the NSOperation class to determine if the operation is running, waiting to run, or already finished.*

apple建议开发者在operation对象被提交到队列后就不要去更改operation对象了,因为它随时会开始执行,如果需要知道operation的状态,通过NSOperation的方法来确定状态。

使用操作队列的几个方法实现任务等待:
```
func operationQueue() {
    let OP1 = NSBlockOperation { () -> Void in
        for i in 0...2 {
            NSLog("task1 - %d",i)
        }
    }
    //OP2执行完成之后的操作
    OP1.completionBlock = { () in
        NSLog("===>>task1 completed<<===")
    }

    let OP2 = NSBlockOperation { () -> Void in
        for i in 0...2 {
            NSLog("task2 - %d",i)
        }
    }

    //添加依赖,OP1执行完毕之后才会执行OP2
    OP2.addDependency(OP1)
    //OP2执行完成之后的操作
    OP2.completionBlock = { () in
        NSLog("===>>task2 completed<<===")
    }

    let OP3 = NSBlockOperation { () -> Void in
        for i in 0...2 {
            NSLog("task3 - %d",i)
        }
    }

    let opQ = NSOperationQueue()
    opQ.addOperations([OP1,OP2], waitUntilFinished: true)
    opQ.addOperation(OP3)
}
```

log信息:
>2016-03-30 17:05:43.303 Mutiple[2363:858459] task1 - 0
2016-03-30 17:05:43.303 Mutiple[2363:858459] task1 - 1
2016-03-30 17:05:43.304 Mutiple[2363:858459] task1 - 2
2016-03-30 17:05:43.304 Mutiple[2363:858459] ===>>task1 completed<<===
2016-03-30 17:05:43.304 Mutiple[2363:858460] task2 - 0
2016-03-30 17:05:43.305 Mutiple[2363:858460] task2 - 1
2016-03-30 17:05:43.305 Mutiple[2363:858460] task2 - 2
2016-03-30 17:05:43.305 Mutiple[2363:858460] ===>>task2 completed<<===
2016-03-30 17:05:43.305 Mutiple[2363:858459] task3 - 0
2016-03-30 17:05:43.307 Mutiple[2363:858459] task3 - 1
2016-03-30 17:05:43.308 Mutiple[2363:858459] task3 - 2


operation queue通过`setMaxConcurrentOperationCount:1`来实现串行队列的功能,但是执行的顺序会根据其他因素来确定,这一点与串行队列又有点不太一样。
>If the execution order of your operation objects is important to you, you should use dependencies to establish that order before adding your operations to a queue

如果需要自己决定执行顺序,使用依赖来实现。

初次之外,operation que还可以暂停operation,通过一个布尔值`suspended`的真和假来决定是否让operation挂起。

当`suspended = YES`,队列不会开启新的operation,但是正在执行的操作会继续运行不会被暂停也不会被取消。这个时候可以继续往队列中添加操作,这些操作同样会处于挂起状态,直到`suspended = NO`。操作只会在结束执行的时候被移除,可以通过KVO观察这个值的变化做相应的操作。

> [阅读原文](http://nucleardev.com/iOS多线程浅汇-实践篇/)

而每条线程都操作自己索要操作的数,如果产生必不可少的言辞将数据复制一客吃另外一长线程处理。

一旦您真正下定狠心要协调管理线程,让Threading Programming
Guide助你吧。

2.2 NSThread使用:

apple提供了区区单方法来使用NSThread:

使用detachNewThreadSelector:toTarget:withObject:

NSThread.detachNewThreadSelector(Selector(“thread”), toTarget:self,
withObject:nil)

应用initWithTarget:selector:object:方法创建线程,但是要手动启动:

let thread =NSThread(target:self, selector:Selector(“thread”) ,
object:nil)thread.start()

打印结果:

2016-03-23 16:51:51.238 Mutiple[9192:3103867] NSThread-(

“{number = 3, name = (null)}”

)

运用performSelectorInBackground: withObject:方法创建并自动启动

遗憾之凡swift无法使用此办法,原因:

The performSelector: method and related selector-invoking methods are
not imported in Swift because they are inherently unsafe.

apple看是点子无是种类安全的。

2.3 NSThread几只常因此底方法:

//获取主线程和手上线程:NSThread.mainThead()NSThread.currentThread()//退出,取消线程NSThread.exit()thread.cancel()//判断线程状态thread.executing//是否以运作thread.finished//是否结束thread.cancelled//是否撤销//判断是否也多线程NSThread.isMultiThread()//使用通知冲线程状态做一些操作NSDidBecomeSingleThreadedNotification//变为单线程NSThreadWillExitNotification//线程即将寿终正寝NSWillBecomeMultiThreadedNotification//即将变为多线程//暂停线程

三、GCD

GCD是apple提出的吗增长多核效率的多线程实现方案,

This technology takes the thread management code you would normally
write in your own applications and moves that code down to the system
level. All you have to do is define the tasks you want to execute and
add them to an appropriate dispatch queue. GCD takes care of creating
the needed threads and of scheduling your tasks to run on those threads

它在网层级帮助开发者维护线程的生命周期,包括线程的缔造、休眠、销毁等,开发者只需要关爱需要贯彻之职能,将急需举行的操作放到调度班(dispatch
queue)中,系统会冲线程的景自行分配资源。

GCD引入了任务(task)和调度班(dispatch queue)的定义。

所谓的职责,其实就算是若若促成之效应和操作,即你如举行呀;

调度班,是贯彻效益的不二法门,简单说就是公想怎么开。

apple列举了dispatch queue的众多长:

提供了又简明的落实多线程的接口,让代码更精简

援助开发者管理线程的生命周期

异步队列中无见面招致死锁

列中之享有任务还按照FIFO的依次执行,GCD提供了三种植队列:

阴差阳错行队列

交互队列

主队列

3.1差行队列

创建

使用dispatch_queue_create(label: UnsafePointer, attr:
dispatch_queue_attr_t)方法创建行,来探望apple对法被之少数只特性的讲:

label:

A string label to attach to the queue to uniquely identify it in
debugging tools such as Instruments, sample, stackshots, and crash
reports. Because applications, libraries, and frameworks can all create
their own dispatch queues, a reverse-DNS naming style
(com.example.myqueue) is recommended. This parameter is optional and can
be NULL.

label是行的名,apple推荐应用com.example.myQueue的平整来定名队列,用于debug的上追踪队列以便于调试,可以啊空

attr:

In OS X v10.7 and later or iOS 4.3 and later, specify
DISPATCH_QUEUE_SERIAL (or NULL) to create a serial queue or specify
DISPATCH_QUEUE_CONCURRENT to create a concurrent queue. In earlier
versions, you must specify NULL for this parameter.

attr用于指定是串行队列还是并行队列,如果是NULL则默认串行队列

letserialQ1 =
dispatch_queue_create(“com.hah.serialQ1”,DISPATCH_QUEUE_SERIAL)或者letserialQ2
= dispatch_queue_create(“com.hah.serialQ2”)

差行队列中的职责会按FIFO的次第依次执行,在共实施下,系统未见面张开新的线程,默认在主线程下执行任务,如果是在异步执行下,系统会冲线程资源气象决定是否打开新的线程。

GCD中得以经过串行队列进行锁线程

来探视同步情况下任务之执行情况:

共同串行:任务一个跟着一个实践,不起头起来新线程;

func syncSerial()

{NSLog(“=======>>>syncSerial<<<========”)      let q1

dispatch_queue_create(“q1”,DISPATCH_QUEUE_SERIAL)dispatch_sync(q1)
{ () -> VoidinNSLog(“1-%@”,NSThread.currentThread());     
}dispatch_sync(q1) { () ->
VoidinNSLog(“2-%@”,NSThread.currentThread());      }dispatch_sync(q1) {
() -> VoidinNSLog(“3-%@”,NSThread.currentThread());     
}dispatch_sync(q1) { () ->
VoidinNSLog(“4-%@”,NSThread.currentThread());      }dispatch_sync(q1) {
() -> VoidinNSLog(“5-%@”,NSThread.currentThread()]);     
}NSLog(“=======>>>syncSerial<<<========”)  }

打印结果:

2016-03-23 13:38:29.521 Mutiple[8199:2165063]
=======>>>syncSerial<<<========

2016-03-23 13:38:29.522 Mutiple[8199:2165063] 1-(

“{number = 1, name = main}”

)

2016-03-23 13:38:29.522 Mutiple[8199:2165063] 2-(

“{number = 1, name = main}”

)

2016-03-23 13:38:29.522 Mutiple[8199:2165063] 3-(

“{number = 1, name = main}”

)

2016-03-23 13:38:29.523 Mutiple[8199:2165063] 4-(

“{number = 1, name = main}”

)

2016-03-23 13:38:29.523 Mutiple[8199:2165063] 5-(

“{number = 1, name = main}”

)

2016-03-23 13:38:29.523 Mutiple[8199:2165063]

=======>>>syncSerial<<<========

异步串行:任务一个随着一个尽,系统基于线程资源情况控制是否打开新的线程;

func asyncSerail()

{NSLog(“=======>>>asyncSerail<<<========”)      let q1

dispatch_queue_create(“q1”,DISPATCH_QUEUE_SERIAL)dispatch_async(q1)
{ () -> VoidinNSLog(“1-%@”,NSThread.currentThread());     
}dispatch_async(q1) { () ->
VoidinNSLog(“2-%@”,NSThread.currentThread());      }dispatch_async(q1)
{ () -> VoidinNSLog(“3-%@”,NSThread.currentThread());     
}dispatch_async(q1) { () ->
VoidinNSLog(“4-%@”,NSThread.currentThread());      }dispatch_async(q1)
{ () -> VoidinNSLog(“5-%@”,NSThread.currentThread());     
}NSLog(“=======>>>asyncSerail<<<========”)  }

打印结果:

2016-03-23 13:04:26.713 Mutiple[7294:1959223]
=======>>>asyncSerail<<<========

2016-03-23 13:04:26.714 Mutiple[7294:1959223]
=======>>>asyncSerail<<<========

2016-03-23 13:04:26.715 Mutiple[7294:1959473] 1-(

“{number = 3, name = (null)}”

)

2016-03-23 13:04:26.716 Mutiple[7294:1959473] 2-(

“{number = 3, name = (null)}”

)

2016-03-23 13:04:26.716 Mutiple[7294:1959473] 3-(

“{number = 3, name = (null)}”

)

2016-03-23 13:04:26.716 Mutiple[7294:1959473] 4-(

“{number = 3, name = (null)}”

)

2016-03-23 13:04:26.716 Mutiple[7294:1959473] 5-(

“{number = 3, name = (null)}”

)

自从打印好望,系统被了初的线程,但是富有的任务还是在和一个线程里好,避免以差不多只线程之间切换。

3.2 并履行队列

互相队列,是大局队列的一律种,它会处理并发任务。apple提供了季个就创造好之竞相队列,又让全局队列(global
queu),开发者只待调用dispatch_get_global_queue( ,
)就能够取得一个交互队列。并行队列同样遵循FIFO的规则执行任务,它同意多独任务并实施,同时实施之任务数系统会根据情况决定。iOS5之后,apple也同意开发者自己创办并行队列。

3.2.1 获取全局队列:

调用dispatch_get_global_queue(identifier: Int, flags:
UInt)方法取得全局队列:

少数只参数:

identifier:

The quality of service you want to give to tasks executed using this
queue. Quality-of-service helps determine the priority given to tasks
executed by the queue. Queues that handle user-interactive or
user-initiated tasks have a higher priority than tasks meant to run in
the background.

identifier用于指定全局队列的优先级,有4种档次:

#defineDISPATCH_QUEUE_PRIORITY_HIGH2#defineDISPATCH_QUEUE_PRIORITY_DEFAULT0#defineDISPATCH_QUEUE_PRIORITY_LOW 
      (-2)#defineDISPATCH_QUEUE_PRIORITY_BACKGROUND  INT16_MIN

iOS 8以后可以透过:

QOS_CLASS_USER_INTERACTIVE,

QOS_CLASS_USER_INITIATED,

QOS_CLASS_UTILITY

QOS_CLASS_BACKGROUND.

来设置优先级。

自打字面上就是会看到,优先级的轻重顺序吗:DISPATCH_QUEUE_PRIORITY_HIGH>DISPATCH_QUEUE_PRIORITY_DEFAULT>DISPATCH_QUEUE_PRIORITY_LOW>DISPATCH_QUEUE_PRIORITY_BACKGROUND

需特别说一下之是,系统建议将关于磁盘的I/0操作放到DISPATCH_QUEUE_PRIORITY_BACKGROUND优先级的队中,防止挤占了多之系统资源。

flags    :

Flags that are reserved for future use. Always specify 0 for this
parameter.

flag默认是0

lethighQ =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)//默认优先级也可以这样形容:letdefaultQ
= dispatch_get_global_queue(0,0)letdefaultQ =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)letlowQ
= dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW,0)letbgQ =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,0)

自己勾勒了段代码模拟了下优先级赛之排先实行的气象:

func queuePriority() {        let highQ =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH,0)       
let defaultQ =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)dispatch_async(defaultQ)
{ () -> VoidinNSLog(“task3 start-%@”,NSThread.currentThread());     
  }dispatch_async(highQ) { () -> VoidinNSLog(“task1
start-%@”,NSThread.currentThread());        }    }

按理说说,应该是预先实行task1,因为它先级比较高,但是log是如此的:

2016-03-24 16:12:49.308 Mutiple[3815:2019744] task3 start-(

“{number = 3, name = (null)}”

)

2016-03-24 16:12:49.308 Mutiple[3815:2019743] task1 start-(

“{number = 4, name = (null)}”

)

先期级赛之非事先实施了,why?

自家为此事先级high和low做了尝试,发现high优先级总是先实施,但是default为什么不怕挺吧?这个小还无懂得。

3.2.2 手动创建并行队列

搭下去手动创建一个彼此队列,查看线程的创造情况:

手拉手并行:任务一个随后一个执,系统默认不开起来新线程;

func syncConcurrency()
{NSLog(“=======>>>syncConcurrency<<<========”)     
let q1 =
dispatch_queue_create(“q1”,DISPATCH_QUEUE_CONCURRENT)dispatch_sync(q1)
{ () -> VoidinNSLog(“1-%@”,NSThread.currentThread());     
}dispatch_sync(q1) { () ->
VoidinNSLog(“2-%@”,NSThread.currentThread());      }dispatch_sync(q1) {
() -> VoidinNSLog(“3-%@”,[NSThread.currentThread()]);     
}dispatch_sync(q1) { () ->
VoidinNSLog(“4-%@”,NSThread.currentThread());      }dispatch_sync(q1) {
() -> VoidinNSLog(“5-%@”,NSThread.currentThread());     
}NSLog(“=======>>>syncConcurrency<<<========”)  }

打印结果:

2016-03-23 13:40:16.968 Mutiple[8256:2181632]
=======>>>syncConcurrency<<<========

2016-03-23 13:40:16.969 Mutiple[8256:2181632] 1-(

“{number = 1, name = main}”

)

2016-03-23 13:40:16.970 Mutiple[8256:2181632] 2-(

“{number = 1, name = main}”

)

2016-03-23 13:40:16.970 Mutiple[8256:2181632] 3-(

“{number = 1, name = main}”

)

2016-03-23 13:40:16.970 Mutiple[8256:2181632] 4-(

“{number = 1, name = main}”

)

2016-03-23 13:40:16.970 Mutiple[8256:2181632] 5-(

“{number = 1, name = main}”

)

2016-03-23 13:40:16.970 Mutiple[8256:2181632]
=======>>>syncConcurrency<<<========

由打印输出可以望,所有任务还是以主线程中就,因为并实施,即使开了大多只线程,下一个的职责或如待当前任务执行完毕才能够开实行,开多个线程之后导致资源浪费。就比如iOS多线程浅汇-原理篇未遭提到的,如果这时段起了三久线程,系统就必须在三长达线程之间切换,除此之外,每条线程都发好的栈和寄存器,三长条线程就出三组的栈和寄存器被复制和替换,这相对于仅仅发雷同漫漫线程来说,效率肯定是大大降低的。

异步并行:多只任务并实施,顺序不定点,但是好透过dispatch_group和NSOperation添加借助控制任务执行顺序。

func asyncConcurrency()
{NSLog(“=======>>>asyncConcurrency<<<========”)     
let q1 =
dispatch_queue_create(“q1”,DISPATCH_QUEUE_CONCURRENT)dispatch_async(q1)
{ () -> VoidinNSLog(“1-%@”,NSThread.currentThread());     
}dispatch_async(q1) { () ->
VoidinNSLog(“2-%@”,NSThread.currentThread();      }dispatch_async(q1) {
() -> VoidinNSLog(“3-%@”,NSThread.currentThread());     
}dispatch_async(q1) { () ->
VoidinNSLog(“4-%@”,NSThread.currentThread());      }dispatch_async(q1)
{ () -> VoidinNSLog(“5-%@”,NSThread.currentThread());     
}NSLog(“=======>>>asyncConcurrency<<<========”)  }

打印结果:

2016-03-23 13:30:20.987 Mutiple[8107:2109033]
=======>>>asyncConcurrency<<<========

2016-03-23 13:30:20.988 Mutiple[8107:2109033]
=======>>>asyncConcurrency<<<========

2016-03-23 13:30:20.989 Mutiple[8107:2109139] 5-(

“{number = 7, name = (null)}”

)

2016-03-23 13:30:20.989 Mutiple[8107:2109119] 3-(

“{number = 4, name = (null)}”

)

2016-03-23 13:30:20.989 Mutiple[8107:2109093] 1-(

“{number = 3, name = (null)}”

)

2016-03-23 13:30:20.989 Mutiple[8107:2109118] 2-(

“{number = 5, name = (null)}”

)

2016-03-23 13:30:20.990 Mutiple[8107:2109138] 4-(

“{number = 6, name = (null)}”

)

异步下开创多独串行队列实现互动效果

func multiAsyncSerail()

{NSLog(“=======>>>asyncSerail<<<========”)      let q1

dispatch_queue_create(“q1”,DISPATCH_QUEUE_SERIAL)dispatch_async(q1)
{ () -> VoidinNSLog(“1-%@”,NSThread.currentThread());      }         
    let q2 =
dispatch_queue_create(“q2”,DISPATCH_QUEUE_SERIAL)dispatch_async(q2)
{ () -> VoidinNSLog(“2-%@”,NSThread.currentThread());      }         
    let q3 =
dispatch_queue_create(“q3”,DISPATCH_QUEUE_SERIAL)dispatch_async(q3)
{ () -> VoidinNSLog(“3-%@”,NSThread.currentThread());      }         
    let q4 =
dispatch_queue_create(“q4”,DISPATCH_QUEUE_SERIAL)dispatch_async(q4)
{ () -> VoidinNSLog(“4-%@”,NSThread.currentThread());      }      let
q5 =
dispatch_queue_create(“q5”,DISPATCH_QUEUE_SERIAL)dispatch_async(q5)
{ () -> VoidinNSLog(“5-%@”,NSThread.currentThread());     
}NSLog(“=======>>>asyncSerail<<<========”)  }

打印结果:

2016-03-23 13:33:21.412 Mutiple[8150:2128078]
=======>>>asyncSerail<<<========

2016-03-23 13:33:21.413 Mutiple[8150:2128078]
=======>>>asyncSerail<<<========

2016-03-23 13:33:21.414 Mutiple[8150:2128320] 4-(

“{number = 7, name = (null)}”

)

2016-03-23 13:33:21.414 Mutiple[8150:2128308] 1-(

“{number = 3, name = (null)}”

)

2016-03-23 13:33:21.414 Mutiple[8150:2128312] 3-(

“{number = 5, name = (null)}”

)

2016-03-23 13:33:21.414 Mutiple[8150:2128321] 5-(

“{number = 6, name = (null)}”

)

2016-03-23 13:33:21.414 Mutiple[8150:2128311] 2-(

“{number = 4, name = (null)}”

)

小结:

使用GCD实现多线程时:

联合串行和协同并行:都见面仍顺序依次执行任务,且未会见开新的线程。

异步串行:会张开新的线程,但是系统默认在同一线程内以职责逐一依次执行,因为这个上起了多只线程也使挨个执行任务,开线程只会造成资源浪费

异步并行:开启多只线程,有差不多只任务而施行,系统会基于各国条线程的事态分配,执行各个不固定。

在异步串行情况下,可以经过创设多独串行队列,实现异步并行的成效,让大多单任务而进行。

3.3 主队列

The main dispatch queue is a globally available serial queue that
executes tasks on the application’s main thread.

主队列是一个全局性的串行队列,用于执行app中主线程的职责,对run
loop起作用,将配属于run
loop的波来与队列任务之实施交织在一块儿(官方文档翻译过来的,太生硬了。。。)。主队列是一个于app来说很重点的同步点,举凡跟UI和用户举报相关的都不能不付出主队列好。这个队是系活动创建的,开发者只待取得队列,并推行操作即可。

抱主线程的方法:

letmainQueue = dispatch_get_main_queue()

最为经常用之:

let queue =
dispatch_get_global_queue(0,0)dispatch_async(queue,{()-> Void in 
//在这里举行片耗时的操作 
dispatch_async(dispatch_get_main_queue(),{()-> Void in     
//刷新UI  })})

3.4 队列组(dispatch group)

Dispatch groups are a way to block a thread until one or more tasks
finish executing.Groups provide a useful synchronization mechanism for
code that depends on the completion of other tasks

使用队列组能够实现为一个或多个任务履行完毕之后又实行下一个任务。

Another way to use dispatch groups is as an alternative to thread joins.

使用队列组将多独任务连续在齐。

用起列组可以在特定的场景下促成有一定的功力,十分诙谐:

进入有三单任务:taks1,task2,taks3。task1与task2没有啊新鲜关系,task3需等待task1和task2结束以后才会开始实践。

使用队列组实现任务等

func dispatchGroup() {      let group = dispatch_group_create()     
let queue1 = dispatch_get_global_queue(0,0)      let queue2 =
dispatch_get_global_queue(0,0)      let queue3 =
dispatch_get_global_queue(0,0)      dispatch_group_async(group,
queue1) { () ->Voidinforiin0..<3{              NSLog(“task1 –
%d”,i)          }      }      dispatch_group_async(group, queue2) { ()
->Voidinforiin0..<3{              NSLog(“task2 – %d”,i)         
}      }      dispatch_group_wait(group, DISPATCH_TIME_FOREVER)     
NSLog(“wait completed”)      dispatch_group_async(group, queue3) { ()
->Voidinforiin0..<3{              NSLog(“task3 – %d”,i)         
}      }  }

log输出:

2016-03-24 22:23:25.717 2016-03-24 22:42:42.465
MultipleThradDemo[49112:4109966] task2 – 0

2016-03-24 22:42:42.465 MultipleThradDemo[49112:4109967] task1 – 0

2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109966] task2 – 1

2016-03-24 22:42:42.467 MultipleThradDemo[49112:4109967] task1 – 1

2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109966] task2 – 2

2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109967] task1 – 2

2016-03-24 22:42:42.468 MultipleThradDemo[49112:4109901] wait
completed

2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 0

2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 1

2016-03-24 22:42:42.469 MultipleThradDemo[49112:4109967] task3 – 2

dispatch_group_wait(group: dispatch_group_t,
timeout:dispatch_time_t):括号里的首先独参数group为等待的班组,第二个timeout为等待的流年

运用队列组的通功能实现上述情景:

func groupNotify() {      let group = dispatch_group_create()      let
queue1 = dispatch_get_global_queue(0,0)      let queue2 =
dispatch_get_global_queue(0,0)      let queue3 =
dispatch_get_global_queue(0,0)      dispatch_group_async(group,
queue1) { () ->Voidinforiin0..<3{              NSLog(“task1 –
%d”,i)          }      }      dispatch_group_async(group, queue2) { ()
->Voidinforiin0..<3{              NSLog(“task2 – %d”,i)         
}      }      dispatch_group_notify(group, queue3) { ()
->VoidinNSLog(“task1、 task2 completed”)foriin0..<3{             
NSLog(“task3 – %d”,i)          }      }  }

log输出:

2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127151] task2 – 0

2016-03-24 23:05:29.010 MultipleThradDemo[49493:4127148] task1 – 0

2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 – 1

2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 – 1

2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127148] task1 – 2

2016-03-24 23:05:29.011 MultipleThradDemo[49493:4127151] task2 – 2

2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task1、 task2
completed

2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 0

2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 1

2016-03-24 23:05:29.012 MultipleThradDemo[49493:4127151] task3 – 2

3.5 GCD的线程安全

尽管GCD本身就是是线程安全之,但是为了还好之以GCD,apple还是于了几乎独建议:

Do not call the dispatch_sync function from a task that is executing on
the same queue that you pass to your function call

在本队列调用dispatch_sync,再用遵循队列传入同步方法会招死锁。

我怀念apple 的意应该是这般的:

func deadLock() {//let q = dispatch_get_global_queue(0, 0)let q =
dispatch_queue_create(“come.multiThread.serialQ”,
DISPATCH_QUEUE_SERIAL)dispatch_async(q) { () -> VoidinNSLog(“1
start-%@”,[NSThread.currentThread()]);dispatch_sync(q, { () ->
VoidinNSLog(“2 start-%@”,[NSThread.currentThread()]);           
})NSLog(“3 start-%@”,[NSThread.currentThread()]);        }NSLog(“4
start-%@”,[NSThread.currentThread()]);    }

只是自己发觉会无会见招致死锁和脚下班是串行还是并行有关。

若是是串行队列,同步执行会阻塞线程,而且串行队列一糟糕只能实行一个职责,q里面等待的职责以及一起阻塞的职责是跟一个职责,造成死锁。

要是互为队列,一坏克履行多个任务,即使一同阻塞了线程,由于可以基本上只任务并实施,q里面没有任务等,不见面造成死锁。

stackoverflow上看似问题之应对:

Usingdispatch_sync()to enqueue a Block to the serial queue on which
you’re already running is guaranteed to deadlock.Usingdispatch_sync()to
enqueue a Block to theconcurrentqueue on which you’re already running
is quite likely to deadlock.

派发同步任务及于正推行之串行队列肯定会促成死锁;派发到互相队列也发十分死的或许导致死锁。所以地方的事例中,并执行队列虽然没有招死锁,还是来高风险的。

note:往主线程派发同任务吗会导致死锁

func mainThreadLock() {        let main =
dispatch_get_main_queue()NSLog(“start-%@”,[NSThread.currentThread()]);dispatch_sync(main)
{ () -> VoidinNSLog(“1 -%@”,[NSThread.currentThread()]);       
}NSLog(“end-%@”,[NSThread.currentThread()]);    }

打印输出:

2016-03-25 10:15:46.638 Mutiple[15813:5558093] start-(

“{number = 1, name = main}”

)

一块任务以及主线程任务相互等待,造成死锁。

Avoid taking locks from the tasks you submit to a dispatch queue.If you
need to synchronize parts of your code, use a serial dispatch queue
instead of a lock.

尽可能不用好锁线程,否则得到的结果可能会见老盖你的预期。使用GCD实现多线程时,apple建议就此串行队列替代线程锁。

文/nuclear(简书作者)

初稿链接:http://www.jianshu.com/p/0f9f7ed53b48

著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。