Swift多線程:使用Thread進行多線程間通信,協調子線程任務

Swift的多線程技術其實和Objective-C沒有區別。Thread是三種正常程序員會使用的多線程中最輕量級的,每個Thread對象表明着一個線程,可是須要本身管理線程的生命週期和線程的同步。線程同步對數據的加鎖會有必定的開銷。html

哪三種正常程序員會使用的多線程方案,問這個的同窗,你,出去~ 前面寫了辣麼多,Operation、GCD、Thread,都忘啦?git

若是要是較真,還有一個多線程技術,叫作pthread。咱們會在最後最後稍微說一下它。可是它絕對不是正常程序員如今還需使用的多線程方案。說完這句話不知道會不會被噴死程序員

1. Thread的三種創建方式

如下全部的代碼都是使用陳舊的Swift 3.0編寫。github

對,你沒看錯。陳舊的Swift 3.0。 Swift 5.0 都開始了,聽到這個消息的時候,心裏是五味雜陳的,有點點爲Swift擔憂了。尼瑪這4.0 發佈沒多久,5.0就開始了。 因此坊間纔有笑話說,學習iOS開發須要熟練使用Swift1.0 , Swift2.0 ,Swif 2.2...四種語言之類的。面試

1.1 使用類方法建立,自動運行

一種是帶Selector,一種不帶。bash

Thread.detachNewThread {
    print("A new thread,name:\(Thread.current)")
}


//帶一個Selector
       Thread.detachNewThreadSelector(#selector(threadPrint), toTarget: self, with: nil)
複製代碼

經過這種方法建立的thread會自動運行。多線程

1.2 實用構造方法創始化,需手動運行

這裏但是使用兩種方法直接建立Thread,並運行。app

Thread(block: <#T##() -> Void#>)
Thread(target: <#T##Any#>, selector: <#T##Selector#>, object: <#T##Any?#>)
複製代碼

下面是個例子,這種方法建立的thread須要手動start運行ide

let customThread = Thread(target: self, selector: #selector(threadPrint), object: nil)
    customThread.start()
複製代碼

1.3 使用NSObject的拓展方法

任何繼承自NSObject的均可以很容易的經過這種方式調用點成方法。post

來,咱們一塊兒來看一下源文件:

extension NSObject {

    
    open func performSelector(onMainThread aSelector: Selector, with arg: Any?, waitUntilDone wait: Bool, modes array: [String]?)

    open func performSelector(onMainThread aSelector: Selector, with arg: Any?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    open func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool, modes array: [String]?)

    @available(iOS 2.0, *)
    open func perform(_ aSelector: Selector, on thr: Thread, with arg: Any?, waitUntilDone wait: Bool)

    
    @available(iOS 2.0, *)
    open func performSelector(inBackground aSelector: Selector, with arg: Any?)
}
複製代碼

2. Thread的基本使用

Thread的基本使用至關簡單,和GCD基本上差很少。也有啓動、暫停、取消、阻塞、設置優先級等等。

方法 做用
start 啓動
cancel 暫停
exit 取消
sleep 阻塞

Thread的經常使用屬性

名稱 用途
name 給線程命名,方便查找
stackSize 棧區大小,看看線程在棧區佔了多大空間
isMainThread 是不是主線程
qualityOfService 服務質量,iOS8.0推出,爲了取代優先級。
  • 說明:thread設置了start後,其實並非立刻就開始運行了。實質上是放進了可調度線程池,等待被CPU調用。線程執行結束以前,狀態可能會在就緒狀態 和 運行狀態 之間來回的切換 就緒狀態 和 運行狀態 之間的狀態切換由CPU來完成,程序員沒法干涉。

  • 阻塞:正在運行thread能夠經過sleep的方式來阻塞線程的執行。

  • 退出:thread在執行完畢以後會自動退出。若是執行了exit,線程會強制退出。有幾點須要注意一下:

    • 不要在主線程中調用啊,會讓UI線程退出的。退出以後看你怎麼搞!
    • 退出以後,這個線程剩下的全部代碼都不會被執行。
    • 調用這個方法以前,必定要注意釋放以前由C語言建立的對象,否則會形成內存泄漏等問題。
  • 取消:這個cancel和GCD同樣的啦,並無真證的取消線程,只是打了一個標誌。取消須要本身的實現。也就是在大人物開始以前,先判斷一下這個標誌位的狀態。要是歷來都沒寫過這個標誌位的狀態判斷,那cancel了也是白瞎。

3. 使用NSCondition實現線程間通信

你們還記得GCD中的信號量(semaphore)嘛?不記得話看看嘍,傳輸門:Swift多線程:GCD進階,單例、信號量、任務組 。Thread裏面的NSCondition和這個有點像。

這個玩意一共就四個方法,咱們索性都來看看:

方法名稱 做用
wait 使線程處於等待狀態
wait(until limit: Date) -> Bool 在給定的時間到達時仍未有信號量出現, 就自動繼續了
signal 喚醒線程
broadcast 喚醒全部等待線程

NSCondition實現了NSLocking協議,因此它自己也有lock和unlock方法。配合在一塊兒能夠解決線程同步的問題,只要在線程開始時加鎖,取得資源後釋放鎖便可。使用時把須要加鎖的代碼放到lockunlock之間就能夠了。

主要不要把什麼亂七八糟的都往加鎖代碼裏面放,放在這個裏面的應該是搶佔資源的讀取和修改。否則一個線程執行的時候另外一個線程就一直在等待,那還要多線程幹哈玩意?!

咱們搞個例子來看看。

需求:

1,模擬下載五張圖片、五篇文章;

2,圖片下載了兩張以後,暫停下載,轉而開啓文章下載;

3,下載三篇文章以後,暫停下載,轉而繼續下載剩下的三張圖片。

4,圖片下載完成後,下載完成剩下的兩篇文章。

說了是模擬啊,因此下載過程就直接print了噢。

class ViewController: UIViewController {
    var downImages: Thread?
    var downArticles: Thread?
    
    let imageCondition = NSCondition()
    let articleCondition = NSCondition()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        downImages = Thread(target: self, selector: #selector(downloadImages), object: nil)
        downArticles = Thread(target: self, selector: #selector(downloadArticles), object: nil)
        downImages?.start()
        
    }
    
    @objc private func threadPrint() {
        Thread.sleep(forTimeInterval: 2)
        print("After 2 seconds, I have been performed. I am \(Thread.current)")
    }
    
    @objc fileprivate func downloadImages() {
        for index in 1...5 {
            print("Downloading No.\(index) image.")
            Thread.sleep(forTimeInterval: 1)
            
            if index == 2 {
                //start downArticles.開啓下載文章的線程
                downArticles?.start()
                
                //Lock the image thread.加鎖,讓下載圖片的線程進入等待狀態
                imageCondition.lock()
                imageCondition.wait()
                imageCondition.unlock()
            }
        }
        print("All images have been completed.")
        
        //Signaling the article when all images completed.
//        等圖片都下載完成以後,激活下載文章的進程
        articleCondition.signal()
    }
    
    @objc fileprivate func downloadArticles() {
        for index in 1...5 {
            print("The No.\(index) article will be downloading.")
            Thread.sleep(forTimeInterval: 1)
            if index == 3 {
                //Signaling the image thread, let it continue to down.
                //激活圖片的線程,讓它繼續下載圖片
                imageCondition.signal()
                
                //Lock the article thread.加鎖,讓下載文章的線程進入等待狀態
                articleCondition.lock()
                articleCondition.wait()
                articleCondition.unlock()
                
            }
        }
        print("There are 5 articles.")
        
    }
}
複製代碼

咱們打印一下最終的打印結果:

好了。最後再說一下基本上沒人用的pthread

4. pthread

其實不知道這個多線程的技術如今還有誰會在用,除了面試可能會偶爾問一下這個名詞。 pthread是POSIX thread的簡寫。表示跨平臺的線程接口。

爲了可以寫Demo,非典型技術宅在浩瀚的Google海洋中游蕩了好久,而後,而後,而後放棄了...

怎麼能這麼不堅持吶,在OC時代曾經仍是能寫出來建立的。因而去看蘋果手冊,而後,而後,而後放棄了...

Threading Programming Guide 。這裏卻是提到了POSIX thread ,還讓人家去看pthread man page。可是,明顯連接被刪除了。

蘋果爸爸。。。好想錘你小胸口。好吧,放棄了。

最後,全部的代碼都放在這裏了:gitHub 下載後給顆Star吧~ 麼麼噠~(~o ̄3 ̄)~ 愛大家~

相關文章
相關標籤/搜索