iOS多線程

iOS多線程

Thread

線程的創(chuàng)建

兩種創(chuàng)建線程的方法 礼旅。常用屬性:

  1. name
  2. Thread.sleep(forTimeInterval: 5)
  3. Thead.current
  4. Thread.main
let threadA = Thread(target: self, selector: #selector(ViewController.run), object: nil)
threadA.start()
let threadB = Thread(block: <#T##() -> Void#>)
threadA.start()

Thread.detachNewThreadSelector(#selector(self.run), toTarget: self, with: nil)
class ThreadTest {
    @objc func run() {
        for i in 0...10 {
            print("----------- curent thread = \(Thread.current.name!)   number = \(i) ----------")
        }
    }
    public func printNumbers() {
        Thread.main.name = "Main"
        for i in 1...5 {
            let thread = Thread(target: self, selector: #selector(self.run), object: nil)
            thread.name = "thread\(i)"
            print("=========== curent thread = \(Thread.current.name!)   child thread = \(thread.name!) ==========")
            thread.start()
        }
    }
}

ThreadTest().printNumbers()

運(yùn)行結(jié)果 :

=========== curent thread = Main   child thread = thread1 ==========
=========== curent thread = Main   child thread = thread2 ==========
----------- curent thread = thread1   number = 0 ----------
----------- curent thread = thread1   number = 1 ----------
----------- curent thread = thread1   number = 2 ----------
----------- curent thread = thread1   number = 3 ----------
----------- curent thread = thread2   number = 0 ----------
----------- curent thread = thread1   number = 4 ----------
----------- curent thread = thread1   number = 5 ----------
----------- curent thread = thread1   number = 6 ----------
=========== curent thread = Main   child thread = thread3 ==========
----------- curent thread = thread2   number = 1 ----------
----------- curent thread = thread2   number = 2 ----------
----------- curent thread = thread1   number = 7 ----------
----------- curent thread = thread2   number = 3 ----------
----------- curent thread = thread1   number = 8 ----------
=========== curent thread = Main   child thread = thread4 ==========
----------- curent thread = thread1   number = 9 ----------
----------- curent thread = thread3   number = 0 ----------
----------- curent thread = thread2   number = 4 ----------
----------- curent thread = thread2   number = 5 ----------
----------- curent thread = thread4   number = 0 ----------
----------- curent thread = thread2   number = 6 ----------
----------- curent thread = thread1   number = 10 ----------
----------- curent thread = thread4   number = 1 ----------
----------- curent thread = thread3   number = 1 ----------
----------- curent thread = thread2   number = 7 ----------
----------- curent thread = thread3   number = 2 ----------
=========== curent thread = Main   child thread = thread5 ==========
----------- curent thread = thread2   number = 8 ----------
----------- curent thread = thread2   number = 9 ----------
----------- curent thread = thread3   number = 3 ----------
----------- curent thread = thread2   number = 10 ----------
----------- curent thread = thread4   number = 2 ----------
----------- curent thread = thread3   number = 4 ----------
----------- curent thread = thread4   number = 3 ----------
----------- curent thread = thread3   number = 5 ----------
----------- curent thread = thread4   number = 4 ----------
----------- curent thread = thread5   number = 0 ----------
----------- curent thread = thread3   number = 6 ----------
----------- curent thread = thread4   number = 5 ----------
----------- curent thread = thread3   number = 7 ----------
----------- curent thread = thread4   number = 6 ----------
----------- curent thread = thread5   number = 1 ----------
----------- curent thread = thread3   number = 8 ----------
----------- curent thread = thread4   number = 7 ----------
----------- curent thread = thread5   number = 2 ----------
----------- curent thread = thread4   number = 8 ----------
----------- curent thread = thread5   number = 3 ----------
----------- curent thread = thread3   number = 9 ----------
----------- curent thread = thread4   number = 9 ----------
----------- curent thread = thread5   number = 4 ----------
----------- curent thread = thread4   number = 10 ----------
----------- curent thread = thread3   number = 10 ----------
----------- curent thread = thread5   number = 5 ----------
----------- curent thread = thread5   number = 6 ----------
----------- curent thread = thread5   number = 7 ----------
----------- curent thread = thread5   number = 8 ----------
----------- curent thread = thread5   number = 9 ----------
----------- curent thread = thread5   number = 10 ----------

線程的退出

退出條件:

  1. 代碼塊執(zhí)行完畢悬包,正常退出
  2. 執(zhí)行代碼塊出錯(cuò)魄梯,異常退出
  3. 調(diào)用exit()方法

主線程沒有辦法直接退出子線程,可以在主線程中給子線程發(fā)送信號(hào)(willExitThread?.cancel()),子線程代碼塊中判斷 Thread.current.isCancelled 屬性,來決定是否退出線程。

class ThreadTest {
    private var willExitThread: Thread?
    @objc private func exitThreadRun()  {
        for i in 0...100 {
            if Thread.current.isCancelled {
                Thread.exit()
            }
            print("current thread name = \(Thread.current.name!)  ----> number = \(i)")
            Thread.sleep(forTimeInterval: 0.5)
        }
    }
    public func exitThread() {
        willExitThread = Thread.init(target: self, selector: #selector(self.exitThreadRun), object: nil)
        willExitThread?.name = "WillExitThread"
        willExitThread?.start()
        Thread.sleep(forTimeInterval: 5)
        willExitThread?.cancel()
    }
}

ThreadTest().exitThread()
current thread name = WillExitThread  ----> number = 0
current thread name = WillExitThread  ----> number = 1
current thread name = WillExitThread  ----> number = 2
current thread name = WillExitThread  ----> number = 3
current thread name = WillExitThread  ----> number = 4
current thread name = WillExitThread  ----> number = 5
current thread name = WillExitThread  ----> number = 6
current thread name = WillExitThread  ----> number = 7
current thread name = WillExitThread  ----> number = 8
current thread name = WillExitThread  ----> number = 9

線程的優(yōu)先級

  1. 默認(rèn)優(yōu)先級0.5
  2. 設(shè)置優(yōu)先級為0---1.0之間的數(shù)字:threadA.threadPriority = 0.01
class ThreadTest {
    @objc func run() {
        for i in 0...10 {
            print("----------- curent thread = \(Thread.current.name!)   number = \(i) ----------")
        }
    }
    public func threadPriority() {
        print("UI thread priority = \(Thread.current.threadPriority)")
        let threadA = Thread(target: self, selector: #selector(self.run), object: nil)
        threadA.name = "threadA"
        print("ThreadA priority = \(Thread.current.threadPriority)")
        threadA.threadPriority = 0.01

        let threadB = Thread(target: self, selector: #selector(self.run), object: nil)
        threadB.name = "threadB"
        print("ThreadB priority = \(Thread.current.threadPriority)")
        threadB.threadPriority = 1.0

        threadA.start()
        threadB.start()
    }
}

ThreadTest().threadPriority()
UI thread priority = 0.5
ThreadA priority = 0.5
ThreadB priority = 0.5
----------- curent thread = threadB   number = 0 ----------
----------- curent thread = threadB   number = 1 ----------
----------- curent thread = threadB   number = 2 ----------
----------- curent thread = threadA   number = 0 ----------
----------- curent thread = threadB   number = 3 ----------
----------- curent thread = threadB   number = 4 ----------
----------- curent thread = threadB   number = 5 ----------
----------- curent thread = threadA   number = 1 ----------
----------- curent thread = threadB   number = 6 ----------
----------- curent thread = threadB   number = 7 ----------
----------- curent thread = threadB   number = 8 ----------
----------- curent thread = threadA   number = 2 ----------
----------- curent thread = threadB   number = 9 ----------
----------- curent thread = threadB   number = 10 ----------
----------- curent thread = threadA   number = 3 ----------
----------- curent thread = threadA   number = 4 ----------
----------- curent thread = threadA   number = 5 ----------
----------- curent thread = threadA   number = 6 ----------
----------- curent thread = threadA   number = 7 ----------
----------- curent thread = threadA   number = 8 ----------
----------- curent thread = threadA   number = 9 ----------
----------- curent thread = threadA   number = 10 ----------

線程同步

線程安全類的特點(diǎn):

  1. 類的實(shí)例可以被多個(gè) 線程安全的訪問
  2. 線程調(diào)用該對象任何方法之后獲得正確的結(jié)果
  3. 線程調(diào)用對象的任何方法计寇,對象保持合理狀態(tài)

不可變類總是線程安全的,可變類則需要提供額外的方法保證其線程安全:

  1. 對會(huì)改變共享資源的方法進(jìn)行線程同步
  2. 區(qū)分運(yùn)行環(huán)境,提供線程安全版本和線程不安全版本番宁。
   objc_sync_enter(self)
   objc_sync_exit(self)
   let lock = NSLock()
   lock.lock()
   lock.unlock()
class Account {
    var accountNumber: String
    var balance: Double
    var lock: NSLock!
    init(_ accountNumber: String, _ balance : Double) {
        self.accountNumber = accountNumber
        self.balance = balance
        self.lock = NSLock()
    }
    func draw(_ drawAmmount : Double)  {
        //            objc_sync_enter(self)
        //            lock.lock()
        if self.balance > drawAmmount {
            print("Thread name = \(Thread.current.name ?? "" ) sucess to draw : \(drawAmmount)")
            Thread.sleep(forTimeInterval: 0.1)
            self.balance -= drawAmmount
            print("Thread name = \(Thread.current.name ?? "" )  balance = \(self.balance)")
        } else {
            print("Thread name = \(Thread.current.name ?? "" ) failed to draw because of  insufficient founds")
        }
        //        lock.unlock()
        //        objc_sync_exit(self)
    }
}

class ThreadTest {
    private var account = Account("123456", 1000)
    public func draw()  {
        let thread1 = Thread(target: self, selector: #selector(self.drawMoneyFromAccount(money:)), object: 800.0)
        thread1.name = "thread1"
        let thread2 = Thread(target: self, selector: #selector(self.drawMoneyFromAccount(money:)), object: 800.0)
        thread2.name = "threa2"
        thread1.start()
        thread2.start()
    }

    @objc private func drawMoneyFromAccount(money : NSNumber)  {
        account.draw(money.doubleValue)
    }
}
Thread name = thread2 sucess to draw : 800.0
Thread name = thread1 sucess to draw : 800.0
Thread name = thread2  balance = 200.0
Thread name = thread1  balance = -600.0
Thread name = thread1 sucess to draw : 800.0
Thread name = thread1  balance = 200.0
Thread name = thread2 failed to draw because of  insufficient founds

線程間通信

iOS提供NSCondition類來提供控制線程通信元莫。其遵守NSLocking協(xié)議也可以用來同步。

  1. wait()方法:當(dāng)前線程等待蝶押,直到被喚醒
  2. singal()方法:任意喚醒一個(gè)在等待的線程
  3. broadcast()方法:喚醒所有等待線程
class Account {
    var accountNumber: String
    var balance: Double
    var lock: NSLock!
    init(_ accountNumber: String, _ balance : Double) {
        self.accountNumber = accountNumber
        self.balance = balance
        self.lock = NSLock()
    }
    func draw(_ drawAmmount : Double)  {
        //            objc_sync_enter(self)
                    lock.lock()
        if self.balance > drawAmmount {
            print("Thread name = \(Thread.current.name ?? "" ) sucess to draw : \(drawAmmount)")
            Thread.sleep(forTimeInterval: 0.1)
            self.balance -= drawAmmount
            print("Thread name = \(Thread.current.name ?? "" )  balance = \(self.balance)")
        } else {
            print("Thread name = \(Thread.current.name ?? "" ) failed to draw because of  insufficient founds")
        }
                lock.unlock()
        //        objc_sync_exit(self)
    }
}

class SavingAccount : Account {
    var condition : NSCondition!
    var flag : Bool = true
    override init(_ accountNumber: String, _ balance: Double) {
        self.condition = NSCondition()
        super.init(accountNumber, balance)
    }
    override func draw(_ drawAmmount: Double) {
        condition.lock()
        if !flag {
            condition.wait()
        } else {
            self.balance -= drawAmmount
            print("Thread name = \(Thread.current.name ?? "" ) sucess to draw : \(drawAmmount)  balance = \(self.balance)")
            flag = false
            condition.broadcast()
        }
        condition.unlock()
    }

    func deposit(money : Double)  {
        condition.lock()
        if flag {
            condition.wait()
        } else {
            self.balance += money
            print("Thread name = \(Thread.current.name ?? "" ) sucess to deposit : \(money) balance = \(self.balance)")
            flag = true
            condition.broadcast()
        }
        condition.unlock()
    }
}

class ThreadTest {
    let savingAccount = SavingAccount("123456", 1000.0)
    public func depositThenDraw() {
        for i in 0..<3 {
            let thread = Thread(target: self, selector: #selector(self.depositMoneyMethod(money:)), object: 800)
            thread.name = "Deposit thread\(i)"
            thread.start()
        }
        let thread = Thread(target: self, selector: #selector(self.drawMoneyMethod(money:)), object: 800)
        thread.name = "draw thread"
        thread.start()
    }
    @objc private  func depositMoneyMethod(money: NSNumber)  {
        for _ in 0..<10 {
            savingAccount.deposit(money: money.doubleValue)
        }
    }
    @objc private func drawMoneyMethod(money: NSNumber)  {
        for _ in 0..<30 {
            savingAccount.draw(money.doubleValue)
        }
    }
}

ThreadTest().depositThenDraw()
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread0 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread1 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread0 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread2 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0
Thread name = Deposit thread0 sucess to deposit : 800.0 balance = 1000.0
Thread name = draw thread sucess to draw : 800.0  balance = 200.0

NSOperation

可以將Operation理解為任務(wù)操作踱蠢,OperationQueue理解為操作隊(duì)列。

open class Operation : NSObject {


    open func start()

    open func main()


    open var isCancelled: Bool { get }

    open func cancel()


    open var isExecuting: Bool { get }

    open var isFinished: Bool { get }

    open var isConcurrent: Bool { get }

    @available(iOS 7.0, *)
    open var isAsynchronous: Bool { get }

    open var isReady: Bool { get }


    open func addDependency(_ op: Operation)

    open func removeDependency(_ op: Operation)


    open var dependencies: [Operation] { get }


    open var queuePriority: Operation.QueuePriority


    @available(iOS 4.0, *)
    open var completionBlock: (() -> Void)?


    @available(iOS 4.0, *)
    open func waitUntilFinished()


    @available(iOS, introduced: 4.0, deprecated: 8.0, message: "Not supported")
    open var threadPriority: Double


    @available(iOS 8.0, *)
    open var qualityOfService: QualityOfService


    @available(iOS 8.0, *)
    open var name: String?
}
extension Operation {

    public enum QueuePriority : Int {

        case veryLow

        case low

        case normal

        case high

        case veryHigh
    }
}

Operation是基于OC封裝的一套管理與執(zhí)行線程操作的類棋电。Operation是抽象類茎截,BlockOperation是其子類,我們也可以繼承Operation封裝自己的操作類赶盔。每個(gè)單獨(dú)的operation有四種狀態(tài)企锌,Ready、Executing于未、Cancelled撕攒、Finished.

class ImageeFilterOperation: Operation {
    var inputImage: UIImage?
    var outputImage: UIImage?
    override func main() {
        outputImage = filter(image: inputImage)
    }
}

blockOperation

BlockOperation是Operation的子類,可以異步執(zhí)行多個(gè)代碼塊烘浦,當(dāng)所有Block都完成抖坪,操作才算完成 。

class OperationTest {
    public func blockOperationDemo() {
        let operation =  BlockOperation {
            for i in 0...10 {
                print("Thread  = \(Thread.current) i = \(i)")
            }
        }
        operation.addExecutionBlock {
            for j in 0...10 {
                print("Thread  = \(Thread.current) j = \(j)")
            }
        }
        let operation2 = BlockOperation {
            for k in 0...10 {
                print("Thread  = \(Thread.current) k = \(k)")
            }
        }
        operation.start()
        operation2.start()
    }
}

OperationTest().blockOperationDemo()
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 0
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 0
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 1
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 1
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 2
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 2
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 3
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 3
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 4
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 4
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 5
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 5
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 6
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 6
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 7
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 7
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 8
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 8
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 9
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 9
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} i = 10
Thread  = <NSThread: 0x6000002329c0>{number = 3, name = (null)} j = 10
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 0
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 1
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 2
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 3
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 4
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 5
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 6
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 7
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 8
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 9
Thread  = <NSThread: 0x600000221640>{number = 1, name = main} k = 10

明顯可以看出:兩個(gè)循環(huán)在不同的線程中執(zhí)行闷叉。使用BlockOperation的最大好處:不需要顯式的操作Thread來管理線程擦俐,BlockOperation會(huì)根據(jù)加入的Block來分配線程,使之異步執(zhí)行片习。但是兩個(gè)Operation之間卻是都是在主線程中按照順序執(zhí)行的捌肴。

操作依賴關(guān)系

操作之間通常存在這一些依賴關(guān)系蹬叭。比如用網(wǎng)絡(luò)請求到的數(shù)據(jù)來渲染界面藕咏,界面的渲染一定會(huì)在請求完成之后執(zhí)行 。

class OperationTest {
    public func operationDependenciesDemo() {
        let operation1 =  BlockOperation {
            for i in 0...10 {
                print("Thread = \(Thread.current) i = \(i)")
            }
        }
        let operation2 = BlockOperation {
            for i in 11...20 {
                print("Thread  = \(Thread.current) i = \(i)")
            }
        }

        let queue = OperationQueue.init()
        //        operation2.addDependency(operation1)
        //        queue.maxConcurrentOperationCount = 1
        queue.addOperation(operation1)
        queue.addOperation(operation2)
    }
}

OperationTest().operationDependenciesDemo()
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 0
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 11
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 12
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 1
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 13
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 2
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 14
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 3
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 15
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 4
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 16
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 5
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 17
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 18
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 6
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 19
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 7
Thread  = <NSThread: 0x600000a3d500>{number = 3, name = (null)} i = 20
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 8
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 9
Thread = <NSThread: 0x600000a20440>{number = 4, name = (null)} i = 10

運(yùn)行結(jié)果如上秽五,因?yàn)镺perationQueue默認(rèn)并行執(zhí)行Operation.如果我們想按順序打印0--20孽查,解決方法是添加依賴:operation2.addDependency(operation1),這樣在operation1完成之后才會(huì)執(zhí)行operation2.

OperationQueue

負(fù)責(zé)安排和運(yùn)行多個(gè)Operation坦喘,單并不局限于FIFO隊(duì)列操作,他提供多個(gè)接口實(shí)現(xiàn)暫停盲再、繼續(xù)、終止瓣铣、優(yōu)先級答朋、依賴等復(fù)雜操作。默認(rèn)并行執(zhí)行已經(jīng)加入的Operation,但是可以通過:

    queue.maxConcurrentOperationCount = 1

來修改其為串行隊(duì)列棠笑。

GCD(Grand Central Dispatch)

GCD是基于c語言的多線程開發(fā)框架梦碗,相比Operation和Thread,GCD更加高效,并且線程由系統(tǒng)管理洪规,會(huì)自動(dòng)啟用多核運(yùn)算印屁。GCD是官方推薦的多線程解決方案。

調(diào)度隊(duì)列

GCD有一個(gè)重要概念調(diào)度隊(duì)列斩例。我們對線程的操作實(shí)際上由調(diào)度隊(duì)列完成雄人,我們只需要把要執(zhí)行的任務(wù)添加到合適的調(diào)度隊(duì)列中即可。

  1. 主隊(duì)列:任務(wù)在主線程中執(zhí)行念赶,會(huì)阻塞線程础钠,是一個(gè)串行隊(duì)列。
  2. 全局并行隊(duì)列叉谜。隊(duì)列中的任務(wù)按照先進(jìn)先出順序執(zhí)行:串行隊(duì)列則一個(gè)任務(wù)結(jié)束才會(huì)開啟另一個(gè)任務(wù)珍坊,并行隊(duì)列則任務(wù)開啟順序和任務(wù)添加順序一致。系統(tǒng)自動(dòng)創(chuàng)建4個(gè)全局共享并行隊(duì)列正罢。
  3. 自定義隊(duì)列:包括串行的和并行的阵漏。
let mainQueue = DispatchQueue.main
print(mainQueue.debugDescription)
var qos: [DispatchQoS.QoSClass] = [.background,.userInitiated,.unspecified,.userInteractive,.default,.unspecified]
for i in 0..<qos.count {
    let queue = DispatchQueue.global(qos: qos[i])
    print(queue.debugDescription)
}
let myQueue = DispatchQueue(label: "self-define queue", qos: DispatchQoS.default, attributes: [DispatchQueue.Attributes.concurrent], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
print(myQueue.debugDescription)
<OS_dispatch_queue_main: com.apple.main-thread[0x111033a80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = com.apple.root.default-qos.overcommit[0x111033f00], width = 0x1, state = 0x001ffe9d00000300, dirty, max qos 5, in-flight = 0, thread = 0x303 }>
<OS_dispatch_queue_global: com.apple.root.background-qos[0x111033c80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_global: com.apple.root.user-initiated-qos[0x111033f80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_global: com.apple.root.default-qos[0x111033e80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_global: com.apple.root.user-interactive-qos[0x111034080] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_global: com.apple.root.default-qos[0x111033e80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_global: com.apple.root.default-qos[0x111033e80] = { xref = -2147483648, ref = -2147483648, sref = 1, target = [0x0], width = 0xfff, state = 0x0060000000000000, in-barrier}>
<OS_dispatch_queue_concurrent: self-define queue[0x600000691280] = { xref = 2, ref = 1, sref = 1, target = com.apple.root.default-qos[0x111033e80], width = 0xffe, state = 0x0000041000000000, in-flight = 0}>

使用隊(duì)列運(yùn)行任務(wù)

開發(fā)者自定義隊(duì)列的是時(shí)候用attributes參數(shù)控制要?jiǎng)?chuàng)建串行隊(duì)列還是并行隊(duì)列。

class DispatchQueueTest {
    public func dispatchQueueDemo() {
//        let  serialQueue = DispatchQueue.init(label: "serial", qos: DispatchQoS.default, attributes: [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
//        serialQueue.async {
//            for i in 1...5 {
//                print("\(Thread.current) i = \(i)")
//            }
//        }
//        serialQueue.async {
//            for i in 1...5 {
//                print("\(Thread.current) i = \(i)")
//            }
//        }
        let  concurrentQueue = DispatchQueue.init(label: "concurrent", qos: DispatchQoS.default, attributes: [.concurrent], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
        concurrentQueue.async {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
        }
        concurrentQueue.async {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
        }
    }
}

DispatchQueueTest().dispatchQueueDemo()

并行隊(duì)列打印結(jié)果:

<NSThread: 0x6000028bfa00>{number = 4, name = (null)} i = 1
<NSThread: 0x6000028bfa40>{number = 5, name = (null)} i = 1
<NSThread: 0x6000028bfa00>{number = 4, name = (null)} i = 2
<NSThread: 0x6000028bfa40>{number = 5, name = (null)} i = 2
<NSThread: 0x6000028bfa00>{number = 4, name = (null)} i = 3
<NSThread: 0x6000028bfa40>{number = 5, name = (null)} i = 3
<NSThread: 0x6000028bfa00>{number = 4, name = (null)} i = 4
<NSThread: 0x6000028bfa40>{number = 5, name = (null)} i = 4
<NSThread: 0x6000028bfa40>{number = 5, name = (null)} i = 5
<NSThread: 0x6000028bfa00>{number = 4, name = (null)} i = 5

串行隊(duì)列打印結(jié)果如下翻具,并且只有一個(gè)線程工作履怯。

<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 1
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 2
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 3
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 4
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 5
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 1
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 2
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 3
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 4
<NSThread: 0x6000036d09c0>{number = 3, name = (null)} i = 5

Sync/Async

Sync: 當(dāng)前任務(wù)加入到隊(duì)列當(dāng)中,等到任務(wù)完成裆泳,線程返回繼續(xù)運(yùn)行叹洲,即會(huì)阻塞線程。
Async:把任務(wù)加入隊(duì)列工禾,立即返回运提,無須等任務(wù)執(zhí)行完成。即不會(huì)阻塞線程 闻葵。
串行隊(duì)列和并行隊(duì)列民泵,都可以執(zhí)行同步任務(wù)和異步任務(wù)。

class DispatchQueueTest {
    public func serialQueueAsyncTasks() {
        let  serialQueue = DispatchQueue.init(label: "serial", qos: DispatchQoS.default, attributes: [], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
        print("SerialQueue------>SyncTasks")
        serialQueue.sync {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }        }
        print("-------- \(Thread.current) ----------")
        serialQueue.sync {
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
        print("SerialQueue------>AsyncTasks")
        serialQueue.async {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
        serialQueue.async {
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
    }
}
SerialQueue------>SyncTasks
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 1
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 2
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 3
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 4
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 5
-------- <NSThread: 0x6000001dd5c0>{number = 1, name = main} ----------
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 6
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 7
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 8
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 9
<NSThread: 0x6000001dd5c0>{number = 1, name = main} i = 10
-------- <NSThread: 0x6000001dd5c0>{number = 1, name = main} ----------
SerialQueue------>AsyncTasks
-------- <NSThread: 0x6000001dd5c0>{number = 1, name = main} ----------
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 1
-------- <NSThread: 0x6000001dd5c0>{number = 1, name = main} ----------
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 2
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 3
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 4
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 5
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 6
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 7
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 8
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 9
<NSThread: 0x6000001f4180>{number = 3, name = (null)} i = 10
class DispatchQueueTest {
    public func concurrentQueueAsyncTasks() {
        let  concurrentQueue = DispatchQueue.init(label: "concurrent", qos: DispatchQoS.default, attributes:[.concurrent], autoreleaseFrequency: DispatchQueue.AutoreleaseFrequency.inherit, target: nil)
        print("concurrentQueue------>SyncTasks")
        concurrentQueue.sync {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }        }
        print("-------- \(Thread.current) ----------")
        concurrentQueue.sync {
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
        print("concurrentQueue------>AsyncTasks")
        concurrentQueue.async {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
        concurrentQueue.async {
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
        }
        print("-------- \(Thread.current) ----------")
    }
}
concurrentQueue------>SyncTasks
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 1
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 2
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 3
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 4
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 5
-------- <NSThread: 0x60000119e8c0>{number = 1, name = main} ----------
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 6
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 7
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 8
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 9
<NSThread: 0x60000119e8c0>{number = 1, name = main} i = 10
-------- <NSThread: 0x60000119e8c0>{number = 1, name = main} ----------
concurrentQueue------>AsyncTasks
-------- <NSThread: 0x60000119e8c0>{number = 1, name = main} ----------
<NSThread: 0x6000011b10c0>{number = 3, name = (null)} i = 1
-------- <NSThread: 0x60000119e8c0>{number = 1, name = main} ----------
<NSThread: 0x600001188040>{number = 4, name = (null)} i = 6
<NSThread: 0x6000011b10c0>{number = 3, name = (null)} i = 2
<NSThread: 0x600001188040>{number = 4, name = (null)} i = 7
<NSThread: 0x6000011b10c0>{number = 3, name = (null)} i = 3
<NSThread: 0x6000011b10c0>{number = 3, name = (null)} i = 4
<NSThread: 0x600001188040>{number = 4, name = (null)} i = 8
<NSThread: 0x6000011b10c0>{number = 3, name = (null)} i = 5
<NSThread: 0x600001188040>{number = 4, name = (null)} i = 9
<NSThread: 0x600001188040>{number = 4, name = (null)} i = 10

根據(jù)上述結(jié)果:由于同步任務(wù)會(huì)阻塞線程槽畔,所以系統(tǒng)不會(huì)新建線程來執(zhí)行開發(fā)者所添加的任務(wù)栈妆,例子中不管串行隊(duì)列還是并行隊(duì)列,都是number = 1的線程厢钧。通俗地講鳞尔,反正要等待,閑著也是閑著早直,不如活都讓你干了寥假。異步任務(wù)不會(huì)阻塞線程,所以添加完任務(wù)之后都會(huì)快速返回number = 1的線程霞扬。這個(gè)時(shí)候體現(xiàn)出了串行隊(duì)列和并行隊(duì)列的區(qū)別:串行隊(duì)列知會(huì)新建一個(gè)線程(number = 3)來執(zhí)行開發(fā)者添加的任務(wù)糕韧,而并行隊(duì)列的話拾给,系統(tǒng)會(huì)根據(jù)需要?jiǎng)?chuàng)建多個(gè)線程(number = 3 && number = 4)來執(zhí)行開發(fā)者添加的任務(wù)。

隊(duì)列組

class DispatchGroupTest {
    public func dispatchGroupDemo() {
        let group = DispatchGroup.init()
        let queue = DispatchQueue.init(label: "my dispatch queue", qos: DispatchQoS.default, attributes: [.concurrent], autoreleaseFrequency: .inherit, target: nil)
        //notify
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
        }
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
        }
        group.notify(queue: .main) {
            for i in 11...15 {
                 print("\(Thread.current) i = \(i)")
            }
        }

        //wait
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            print("\(Thread.current)   Time-consuming task one")
            Thread.sleep(forTimeInterval: 2)
        }
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            print("\(Thread.current)   Time-consuming task two")
            Thread.sleep(forTimeInterval: 2)

        }
        let result = group.wait(timeout: DispatchTime.now() + 5)
        switch result {
        case .success:
            print("Wonderful! Finished two tasks!")
        case .timedOut:
            print("Timeout! Failed to excute last two tasks!")
        }

        //enter && leave
        group.enter()
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            print("\(Thread.current)   Time-consuming task one")
            for i in 1...5 {
                print("\(Thread.current) i = \(i)")
            }
            group.leave()
        }
        group.enter()
        queue.async(group: group, qos: DispatchQoS.default, flags: []) {
            print("\(Thread.current)   Time-consuming task two")
            for i in 6...10 {
                print("\(Thread.current) i = \(i)")
            }
            group.leave()
        }
        group.notify(queue: .main) {
            print("\(Thread.current)   Time-consuming task three")
            for i in 11...15 {
                print("\(Thread.current) i = \(i)")
            }
        }
    }
}
DispatchGroupTest().dispatchGroupDemo()

三段代碼分別的運(yùn)行結(jié)果:

<NSThread: 0x600001a95e40>{number = 3, name = (null)} i = 1
<NSThread: 0x600001a9da40>{number = 4, name = (null)} i = 6
<NSThread: 0x600001a9da40>{number = 4, name = (null)} i = 7
<NSThread: 0x600001a95e40>{number = 3, name = (null)} i = 2
<NSThread: 0x600001a9da40>{number = 4, name = (null)} i = 8
<NSThread: 0x600001a95e40>{number = 3, name = (null)} i = 3
<NSThread: 0x600001a9da40>{number = 4, name = (null)} i = 9
<NSThread: 0x600001a95e40>{number = 3, name = (null)} i = 4
<NSThread: 0x600001a9da40>{number = 4, name = (null)} i = 10
<NSThread: 0x600001a95e40>{number = 3, name = (null)} i = 5
<NSThread: 0x600001aba800>{number = 1, name = main} i = 11
<NSThread: 0x600001aba800>{number = 1, name = main} i = 12
<NSThread: 0x600001aba800>{number = 1, name = main} i = 13
<NSThread: 0x600001aba800>{number = 1, name = main} i = 14
<NSThread: 0x600001aba800>{number = 1, name = main} i = 15
<NSThread: 0x6000033dafc0>{number = 3, name = (null)}   Time-consuming task one
<NSThread: 0x6000033d41c0>{number = 4, name = (null)}   Time-consuming task two
Wonderful! Finished two tasks!
<NSThread: 0x600003d0f400>{number = 3, name = (null)}   Time-consuming task one
<NSThread: 0x600003d35740>{number = 4, name = (null)}   Time-consuming task two
<NSThread: 0x600003d35740>{number = 4, name = (null)} i = 6
<NSThread: 0x600003d0f400>{number = 3, name = (null)} i = 1
<NSThread: 0x600003d35740>{number = 4, name = (null)} i = 7
<NSThread: 0x600003d0f400>{number = 3, name = (null)} i = 2
<NSThread: 0x600003d35740>{number = 4, name = (null)} i = 8
<NSThread: 0x600003d35740>{number = 4, name = (null)} i = 9
<NSThread: 0x600003d0f400>{number = 3, name = (null)} i = 3
<NSThread: 0x600003d0f400>{number = 3, name = (null)} i = 4
<NSThread: 0x600003d35740>{number = 4, name = (null)} i = 10
<NSThread: 0x600003d0f400>{number = 3, name = (null)} i = 5
<NSThread: 0x600003d1e500>{number = 1, name = main}   Time-consuming task three
<NSThread: 0x600003d1e500>{number = 1, name = main} i = 11
<NSThread: 0x600003d1e500>{number = 1, name = main} i = 12
<NSThread: 0x600003d1e500>{number = 1, name = main} i = 13
<NSThread: 0x600003d1e500>{number = 1, name = main} i = 14
<NSThread: 0x600003d1e500>{number = 1, name = main} i = 15

GCD處理循環(huán)任務(wù)

根據(jù)打印結(jié)果兔沃,我的電腦大約有70個(gè)線程來執(zhí)行代碼塊蒋得。

let queue = DispatchQueue.global()
for i in 0...1000 {
    queue.async {
        print("\(Thread.current) Time-consuming task \(i)")
        Thread.sleep(forTimeInterval: 0.5)
    }
}

GCD的消息和信號(hào)量

class DispatchSourceAndSemaphoreTest {
    public func DispatchSourceAndSemaphoreDemo() {
        let source =  DispatchSource.makeUserDataAddSource(queue: DispatchQueue.global())
        source.setEventHandler {
            print("Received Info!")
        }
        source.activate()
        source.add(data: 1)

        let semaphore = DispatchSemaphore.init(value: 0)
        let queue = DispatchQueue.global()
        queue.async {
            Thread.sleep(forTimeInterval: 3)
            semaphore.signal()
        }
        let start = Date()
        semaphore.wait()
        print("After \(Date().timeIntervalSince(start)) seconds, dispatchSemaphore test !")
    }
}

DispatchSourceAndSemaphoreTest().DispatchSourceAndSemaphoreDemo()
Received Info!
After 3.0051910877227783 seconds, dispatchSemaphore test !

GCD執(zhí)行延時(shí)任務(wù)

class DispatchQueueTest {
    public func DispatchQueueDemo() {
        let queue = DispatchQueue.global()
        let start = Date()
        queue.asyncAfter(deadline: DispatchTime.now() + 3.0) {
            print("After \(Date().timeIntervalSince(start)) seconds, block start to execute.")
        }
    }
}
DispatchQueueTest().DispatchQueueDemo()

并發(fā)編程三大問題

競態(tài)條件

指的是兩個(gè)或者兩個(gè)以上的線程對共享資源進(jìn)行讀寫操作,最終導(dǎo)致結(jié)果不確定乒疏。

class ConcurrentProgramProblem {
    public func raceConditionTest() -> Int {
        var num = 0
        DispatchQueue.global().async {
            for i in 0...50 {
                num += i
            }
        }
        for i in 0...50 {
            num += i
        }
        return num
    }
}
var ans = ""
for _ in 0...10 {
    ans += "  \(ConcurrentProgramProblem().raceConditionTest())  "
}
print(ans)
  1803    2178    2310    2181    2310    2451    2517    2500    2550    2550    1710 

Priority Inverstion(優(yōu)先倒置)

class ConcurrentProgramProblem {
    public func priorityInverstionTest() {
        let lowPriorityQueue = DispatchQueue(label: "Low Priority", qos: .utility, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
        let highPriorityQueue = DispatchQueue(label: "High Priority", qos: .userInitiated, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)
        let semaphore = DispatchSemaphore.init(value: 1)

        lowPriorityQueue.async {
//            semaphore.wait()
            for i in 0...10 {
                print("\(Thread.current)  i = \(i)")
            }
//            semaphore.signal()
        }
        highPriorityQueue.async {
//            semaphore.wait()
            for i in 11...20 {
                print("\(Thread.current)  i = \(i)")
            }
//            semaphore.signal()
        }
    }
}
ConcurrentProgramProblem().priorityInverstionTest()

明顯優(yōu)先級高的先執(zhí)行完额衙。

<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 11
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 0
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 12
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 13
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 14
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 15
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 1
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 16
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 17
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 2
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 18
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 3
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 19
<NSThread: 0x6000013a7a40>{number = 4, name = (null)}  i = 20
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 4
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 5
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 6
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 7
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 8
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 9
<NSThread: 0x6000013a7b00>{number = 3, name = (null)}  i = 10

加入信號(hào)量:

<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 0
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 1
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 2
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 3
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 4
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 5
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 6
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 7
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 8
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 9
<NSThread: 0x6000035d06c0>{number = 3, name = (null)}  i = 10
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 11
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 12
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 13
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 14
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 15
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 16
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 17
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 18
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 19
<NSThread: 0x6000035d9ec0>{number = 6, name = (null)}  i = 20

Dead Lock(死鎖問題)

兩個(gè)或者多個(gè) 線程等待彼此執(zhí)行結(jié)束,以獲得某種資源怕吴,但是沒有一方會(huì)提前退出窍侧。

class ConcurrentProgramProblem {
    public func deadLockTest() {
        let operationA = BlockOperation()
        let operationB = BlockOperation()
        operationA.addDependency(operationB)
        operationB.addDependency(operationA)

        let serialQueue = DispatchQueue.init(label: "Serial Queue")
        serialQueue.sync {
            serialQueue.sync {
                print("!!!!")
            }
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市转绷,隨后出現(xiàn)的幾起案子伟件,更是在濱河造成了極大的恐慌,老刑警劉巖议经,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斧账,死亡現(xiàn)場離奇詭異,居然都是意外死亡煞肾,警方通過查閱死者的電腦和手機(jī)咧织,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來籍救,“玉大人习绢,你說我怎么就攤上這事◎迹” “怎么了闪萄?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長奇颠。 經(jīng)常有香客問我败去,道長,這世上最難降的妖魔是什么大刊? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任为迈,我火速辦了婚禮,結(jié)果婚禮上缺菌,老公的妹妹穿的比我還像新娘。我一直安慰自己搜锰,他們只是感情好伴郁,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蛋叼,像睡著了一般焊傅。 火紅的嫁衣襯著肌膚如雪剂陡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天狐胎,我揣著相機(jī)與錄音鸭栖,去河邊找鬼。 笑死握巢,一個(gè)胖子當(dāng)著我的面吹牛晕鹊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播暴浦,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼溅话,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了歌焦?” 一聲冷哼從身側(cè)響起飞几,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎独撇,沒想到半個(gè)月后屑墨,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡纷铣,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年绪钥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片关炼。...
    茶點(diǎn)故事閱讀 39,977評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡程腹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出儒拂,到底是詐尸還是另有隱情寸潦,我是刑警寧澤,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布社痛,位于F島的核電站见转,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蒜哀。R本人自食惡果不足惜斩箫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望撵儿。 院中可真熱鬧乘客,春花似錦、人聲如沸淀歇。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽浪默。三九已至牡直,卻和暖如春缀匕,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背碰逸。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工乡小, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人饵史。 一個(gè)月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓满钟,卻偏偏與公主長得像,于是被迫代替她去往敵國和親约急。 傳聞我的和親對象是個(gè)殘疾皇子零远,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 一、前言 上一篇文章iOS多線程淺匯-原理篇中整理了一些有關(guān)多線程的基本概念厌蔽。本篇博文介紹的是iOS中常用的幾個(gè)多...
    nuclear閱讀 2,050評論 6 18
  • 多線程基本概念 單核CPU牵辣,同一時(shí)間cpu只能處理1個(gè)線程,只有1個(gè)線程在執(zhí)行 。多線程同時(shí)執(zhí)行:是CPU快速的在...
    WeiHing閱讀 708評論 1 5
  • 主隊(duì)列 細(xì)心的同學(xué)就會(huì)發(fā)現(xiàn)奴饮,每套多線程方案都會(huì)有一個(gè)主線程(當(dāng)然啦纬向,說的是iOS中,像 pthread 這種多系統(tǒng)...
    京北磊哥閱讀 379評論 0 1
  • 學(xué)習(xí)多線程戴卜,轉(zhuǎn)載兩篇大神的帖子逾条,留著以后回顧!第一篇:關(guān)于iOS多線程投剥,你看我就夠了 第二篇:GCD使用經(jīng)驗(yàn)與技巧...
    John_LS閱讀 620評論 0 3
  • 獻(xiàn)身挑戰(zhàn) 能量挑戰(zhàn)魅力大师脂, 讓我魂?duì)繅衾飹欤?就等融冰踹倆下, 凌晨三點(diǎn)寫刷刷。
    磊磊18閱讀 85評論 0 0