Swift - NSThread線程相關(guān)簡單說明

說明

1)關(guān)于多線程部分的理論知識和Swift實現(xiàn)。
2)該文僅僅簡單講解NSThread在Swift語境中的一些使用和注意點,別他。

NSThread的基本使用和創(chuàng)建

基本用法(主線程|當(dāng)前線程)

        // 獲得執(zhí)行該方法的當(dāng)前線程
        let currentThread = NSThread.currentThread
        // 當(dāng)前線程為:(Function)
        print("當(dāng)前線程為:\(currentThread)")
        
        // 獲得應(yīng)用程序的主線程
        let mainThread = NSThread.mainThread()
        // 應(yīng)用程序的主線程:<NSThread: 0x7c973710>{number = 1, name = main}
        print("應(yīng)用程序的主線程:\(mainThread)")
        
        // 判斷當(dāng)前線程是否是主線程
        let isMain = NSThread.isMainThread()
        print(isMain)  // return:true

創(chuàng)建線程

說明:此處列出創(chuàng)建線程的四種方法:分別是

直接創(chuàng)建|分離出一條子線程|創(chuàng)建一條后臺線程|自定義線程類繼承自NSThread重寫內(nèi)部的main方法封裝任務(wù),然后init創(chuàng)建。

    // NSThread創(chuàng)建線程的四種方式
    func createNewThreadWithNSThreadMethodOne() {
        // 創(chuàng)建線程
        let thread = NSThread.init(target: self, selector: Selector("run"), object: nil)
        // 設(shè)置線程的名稱
        thread.name = "線程A"
        // 啟動線程
        thread.start()
    }
    
    func createNewThreadWithNSThreadMethodTwo() {
        // 分離出一條子線程,自動啟動線程,但無法獲得線程對象
        NSThread.detachNewThreadSelector(Selector("run"), toTarget: self, withObject: nil)
    }
    
    func createNewThreadWithNSThreadMethodThree() {
        // 開啟一條后臺線程,自動啟動線程,但無法獲得線程對象
        self.performSelectorInBackground(Selector("run"), withObject: nil)
    }
    
    func createNewThreadWithNSThreadMethodFour() {
        let thread = CustomThread()
        thread.start()
        
    }
    
    func run() {
        // 獲得當(dāng)前執(zhí)行run方法的線程
        let thread = NSThread.currentThread()
        print("run--\(thread.name)-\(thread)")
    }

NSThread線程的狀態(tài)和線程安全

線程的狀態(tài)

線程的狀態(tài):新建-就緒-運行-阻塞-死亡

        // 程的退出
        NSThread.exit()
        // 線程的休眠1
        NSThread.sleepForTimeInterval(2.0)
        // 線程的休眠2
        NSThread.sleepUntilDate(NSDate.init(timeIntervalSinceNow: 3.0))

線程安全

說明:多線程訪問同一個資源的時候可能會出現(xiàn)數(shù)據(jù)錯亂等安全問題,解決方法是對必要的代碼段進行加鎖。
注意:在OC中加互斥鎖使用@synchronized(self) {},
在swift可以使用objc_sync_enter(self)和objc_sync_exit(self)方法,
注意這兩個方法必須成對使用,把要加鎖的代碼放在中間

//
//  ViewController.swift
//  Programming in Swift
//
//  Created by ChenQianPing on 16/5/23.
//  Copyright ? 2016年 ChenQianPing. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    // 設(shè)置總票數(shù)為100張
    var totalTickets = 100

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // 多線程訪問資源加鎖
        // 創(chuàng)建三條線程分別代表售票員A、售票員B、售票員C
        let thread01 = NSThread.init(target: self, selector:Selector("saleTickect"), object: nil)
        let thread02 = NSThread.init(target: self, selector: Selector("saleTickect"), object: nil);
        let thread03 = NSThread.init(target: self, selector: Selector("saleTickect"), object: nil);
        
        // 設(shè)置線程的名稱
        thread01.name = "售票員A"
        thread02.name = "售票員B"
        thread03.name = "售票員C"
        
        // 開啟線程
        thread01.start()
        thread02.start()
        thread03.start()
        
    }
    
    // 模擬售票的函數(shù)
    func saleTickect() {
        while(true) {
            
            // 加互斥鎖
            /* 
            * 1)同OC中的@synchronized(self) {}
            * 2)objc_sync_enter(self)和objc_sync_exit(self)必須成對使用,把要加鎖的代碼放在中間
            */
            objc_sync_enter(self)
            
            // 檢查是否有余票,如果有則賣出去一張
            let temp = totalTickets
            for var i=0;i<100000;i++ {
                // 空的for循環(huán),模擬延遲
            }
            if(temp > 0) {
                totalTickets = temp - 1
                print("\(NSThread.currentThread().name)賣出去了一張票,還剩\(totalTickets)")
            } else {
                print("\(NSThread.currentThread().name)發(fā)現(xiàn)票已經(jīng)賣完了")
                break
            }
            objc_sync_exit(self)
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

Optional("售票員A")賣出去了一張票,還剩99
Optional("售票員B")賣出去了一張票,還剩98
Optional("售票員C")賣出去了一張票,還剩97
Optional("售票員A")賣出去了一張票,還剩96
Optional("售票員B")賣出去了一張票,還剩95
Optional("售票員C")賣出去了一張票,還剩94
Optional("售票員A")賣出去了一張票,還剩93
Optional("售票員B")賣出去了一張票,還剩92
Optional("售票員C")賣出去了一張票,還剩91
Optional("售票員A")賣出去了一張票,還剩90
Optional("售票員B")賣出去了一張票,還剩89
Optional("售票員C")賣出去了一張票,還剩88
Optional("售票員A")賣出去了一張票,還剩87
Optional("售票員B")賣出去了一張票,還剩86
Optional("售票員C")賣出去了一張票,還剩85
Optional("售票員A")賣出去了一張票,還剩84
Optional("售票員B")賣出去了一張票,還剩83
Optional("售票員C")賣出去了一張票,還剩82
Optional("售票員A")賣出去了一張票,還剩81
Optional("售票員B")賣出去了一張票,還剩80
Optional("售票員C")賣出去了一張票,還剩79
Optional("售票員A")賣出去了一張票,還剩78
Optional("售票員B")賣出去了一張票,還剩77
Optional("售票員C")賣出去了一張票,還剩76
Optional("售票員A")賣出去了一張票,還剩75
Optional("售票員B")賣出去了一張票,還剩74
Optional("售票員C")賣出去了一張票,還剩73
Optional("售票員A")賣出去了一張票,還剩72
Optional("售票員B")賣出去了一張票,還剩71
Optional("售票員C")賣出去了一張票,還剩70
Optional("售票員A")賣出去了一張票,還剩69
Optional("售票員B")賣出去了一張票,還剩68
Optional("售票員C")賣出去了一張票,還剩67
Optional("售票員A")賣出去了一張票,還剩66
Optional("售票員B")賣出去了一張票,還剩65
Optional("售票員C")賣出去了一張票,還剩64
Optional("售票員A")賣出去了一張票,還剩63
Optional("售票員B")賣出去了一張票,還剩62
Optional("售票員C")賣出去了一張票,還剩61
Optional("售票員A")賣出去了一張票,還剩60
Optional("售票員B")賣出去了一張票,還剩59
Optional("售票員C")賣出去了一張票,還剩58
Optional("售票員A")賣出去了一張票,還剩57
Optional("售票員B")賣出去了一張票,還剩56
Optional("售票員C")賣出去了一張票,還剩55
Optional("售票員A")賣出去了一張票,還剩54
Optional("售票員B")賣出去了一張票,還剩53
Optional("售票員C")賣出去了一張票,還剩52
Optional("售票員A")賣出去了一張票,還剩51
Optional("售票員B")賣出去了一張票,還剩50
Optional("售票員C")賣出去了一張票,還剩49
Optional("售票員A")賣出去了一張票,還剩48
Optional("售票員B")賣出去了一張票,還剩47
Optional("售票員C")賣出去了一張票,還剩46
Optional("售票員A")賣出去了一張票,還剩45
Optional("售票員B")賣出去了一張票,還剩44
Optional("售票員C")賣出去了一張票,還剩43
Optional("售票員A")賣出去了一張票,還剩42
Optional("售票員B")賣出去了一張票,還剩41
Optional("售票員C")賣出去了一張票,還剩40
Optional("售票員A")賣出去了一張票,還剩39
Optional("售票員B")賣出去了一張票,還剩38
Optional("售票員C")賣出去了一張票,還剩37
Optional("售票員A")賣出去了一張票,還剩36
Optional("售票員B")賣出去了一張票,還剩35
Optional("售票員C")賣出去了一張票,還剩34
Optional("售票員A")賣出去了一張票,還剩33
Optional("售票員B")賣出去了一張票,還剩32
Optional("售票員C")賣出去了一張票,還剩31
Optional("售票員A")賣出去了一張票,還剩30
Optional("售票員B")賣出去了一張票,還剩29
Optional("售票員C")賣出去了一張票,還剩28
Optional("售票員A")賣出去了一張票,還剩27
Optional("售票員B")賣出去了一張票,還剩26
Optional("售票員C")賣出去了一張票,還剩25
Optional("售票員A")賣出去了一張票,還剩24
Optional("售票員B")賣出去了一張票,還剩23
Optional("售票員C")賣出去了一張票,還剩22
Optional("售票員A")賣出去了一張票,還剩21
Optional("售票員B")賣出去了一張票,還剩20
Optional("售票員C")賣出去了一張票,還剩19
Optional("售票員A")賣出去了一張票,還剩18
Optional("售票員B")賣出去了一張票,還剩17
Optional("售票員C")賣出去了一張票,還剩16
Optional("售票員A")賣出去了一張票,還剩15
Optional("售票員B")賣出去了一張票,還剩14
Optional("售票員C")賣出去了一張票,還剩13
Optional("售票員A")賣出去了一張票,還剩12
Optional("售票員B")賣出去了一張票,還剩11
Optional("售票員C")賣出去了一張票,還剩10
Optional("售票員A")賣出去了一張票,還剩9
Optional("售票員B")賣出去了一張票,還剩8
Optional("售票員C")賣出去了一張票,還剩7
Optional("售票員A")賣出去了一張票,還剩6
Optional("售票員B")賣出去了一張票,還剩5
Optional("售票員C")賣出去了一張票,還剩4
Optional("售票員A")賣出去了一張票,還剩3
Optional("售票員B")賣出去了一張票,還剩2
Optional("售票員C")賣出去了一張票,還剩1
Optional("售票員A")賣出去了一張票,還剩0
Optional("售票員B")發(fā)現(xiàn)票已經(jīng)賣完了

NSThread線程間通信

說明

所謂線程間通信,即如何從一個線程進入到另一個線程繼續(xù)執(zhí)行任務(wù)或者是傳遞參數(shù)(如從子線程回到主線程)

下面的代碼示例演示在主線程中先創(chuàng)建一個子線程下載圖片,當(dāng)圖片下載完成后又切換到主線程設(shè)置圖片的操作。

import UIKit

class ViewController: UIViewController {
    
    @IBOutlet weak var imageView: UIImageView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        // 程序啟動后開子線程下載圖片,圖片下載完成之后回到主線程設(shè)置圖片
        NSThread.detachNewThreadSelector(Selector("downloadImage"), toTarget: self, withObject: nil)
        
    }
    
    func downloadImage() {
        // 獲得要下載圖片的url
        let url = NSURL.init(string: "http://cdn.cocimg.com/assets/images/logo.png")
        // 把url地址指向資源的二進制下載到本地
        let imageData = NSData.init(contentsOfURL: url!)
        // 把二進制數(shù)據(jù)轉(zhuǎn)換為圖片
        let image = UIImage.init(data: imageData!)
        
        // 打印查看當(dāng)前線程(應(yīng)該是在子線程中下載圖片)
        print("當(dāng)前線程為\(NSThread.currentThread())")

        // 線程間通信
        self.performSelectorOnMainThread(Selector("showImage:"), withObject: image, waitUntilDone:true)
        
    }
    
    func showImage(image:UIImage) {
        imageView.image = image
        print("處理UI刷新操作的線程:\(NSThread.currentThread())")
    }
    
  
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }


}

當(dāng)前線程為<NSThread: 0x7be77880>{number = 2, name = (null)}
處理UI刷新操作的線程:<NSThread: 0x7c171150>{number = 1, name = main}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容