1. 程式人生 > >NSThread 執行緒相關簡單說明(一些使用和注意點)

NSThread 執行緒相關簡單說明(一些使用和注意點)

一 說明

本文涉及程式碼可以從https://github.com/HanGangAndHanMeimei/Code地址獲得。

二 NSThread的基本使用和建立

  1)基本用法(主執行緒|當前執行緒)

複製程式碼
 1        //1.獲得執行該方法的當前執行緒
 2         let currentThread = NSThread.currentThread()
 3         print("當前執行緒為\(currentThread)")
 4 
 5         //2.獲得應用程式的主執行緒
 6         let mainThread = NSThread.mainThread()
7 print("應用程式的主執行緒\(mainThread)") 8 9 //3.判斷當前執行緒是否是主執行緒 10 let isMain = NSThread.isMainThread()

2)建立執行緒

  說明:此處列出建立執行緒的四種方法:分別是

  直接建立|分離出一條子執行緒|建立一條後臺執行緒|自定義執行緒類繼承自NSThread重寫內部的main方法封裝任務,然後init建立。

複製程式碼
 1 //NSThread建立執行緒的四種方式
 2     func createNewThreadWithNSThreadMethodOne()
3 { 4 //1.建立執行緒 5 let thread = NSThread.init(target: self, selector:Selector("run"), object: nil) 6 7 //設定執行緒的名稱 8 thread.name = "執行緒A" 9 10 //2.啟動執行緒 11 thread.start() 12 } 13 14 func createNewThreadWithNSThreadMethodTwo() 15 { 16 //
分離出一條子執行緒,自動啟動執行緒,但無法獲得執行緒物件 17 NSThread.detachNewThreadSelector(Selector("run"), toTarget: self, withObject: nil) 18 } 19 20 func createNewThreadWithNSThreadMethodThree() 21 { 22 //開啟一條後臺執行緒,自動啟動執行緒,但無法獲得執行緒物件 23 self.performSelectorInBackground(Selector("run"), withObject: nil); 24 } 25 26 func createNewThreadWithNSThreadMethodFour() 27 { 28 //let thread = CustomThread.init(target: self, selector:Selector("run"), object: nil) 29 let thread = CustomThread(); 30 thread.start() 31 } 32 33 func run() 34 { 35 //獲得當前執行run方法的執行緒 36 let thread = NSThread.currentThread() 37 print("run--\(thread.name)-\(thread)"); 38 }
複製程式碼

三 NSThread執行緒的狀態和執行緒安全

1)執行緒的狀態

    執行緒的狀態:新建-就緒-執行-阻塞-死亡

1      //執行緒的退出
2         NSThread.exit()
3         //執行緒的休眠1
4         NSThread.sleepForTimeInterval(2.0)
5         //執行緒的休眠2
6         NSThread.sleepUntilDate(NSDate.init(timeIntervalSinceNow: 3.0))

  2)執行緒安全

    說明:多執行緒訪問同一個資源的時候可能會出現資料錯亂等安全問題,解決方法是對必要的程式碼段進行加鎖。

    注意:在OC中加互斥鎖使用@synchronized(self) {},在swift可以使用objc_sync_enter(self)和objc_sync_exit(self)方法,注意這兩個方法必須成對使用,把要加鎖的程式碼放在中間

複製程式碼
 1 class ViewController: UIViewController {
 2 
 3     //設定總票數為100張
 4     var totalTickets = 100
 5 
 6     override func viewDidLoad() {
 7         super.viewDidLoad()
 8 
 9         //多執行緒訪問資源加鎖
10         //建立三條執行緒分別代表售票員A、售票員B、售票員C
11         let thread01 = NSThread.init(target: self, selector:Selector("saleTickect"), object: nil)
12         let thread02 = NSThread.init(target: self, selector: Selector("saleTickect"), object: nil);
13         let thread03 = NSThread.init(target: self, selector: Selector("saleTickect"), object: nil);
14 
15         //設定執行緒的名稱
16         thread01.name = "售票員A"
17         thread02.name = "售票員B"
18         thread03.name = "售票員C"
19 
20         //開啟執行緒
21         thread01.start()
22         thread02.start()
23         thread03.start()
24 
25     }
26 
27     //模擬售票的函式
28     func saleTickect()
29     {
30         while(true)
31         {
32             //加互斥鎖
33             /*
34             * 1)同OC中的@synchronized(self) {}
35             * 2)objc_sync_enter(self)和objc_sync_exit(self)必須成對使用,把要加鎖的程式碼放在中間
36             */
37 
38             objc_sync_enter(self)
39 
40             //檢查是否有餘票,如果有則賣出去一張
41             let temp = totalTickets
42             for var i=0;i<100000;i++
43             {
44                 //空的for迴圈,模擬延遲
45             }
46 
47             if(temp>0)
48             {
49                 totalTickets = temp - 1
50                 print("\(NSThread.currentThread().name)賣出去了一張票,還剩\(totalTickets)")
51             }else
52             {
53                 print("\(NSThread.currentThread().name)發現票已經賣完了")
54                 break;
55             }
56             
57             objc_sync_exit(self)
58         }
59         
60     }
61     
62 }
複製程式碼

三 NSThread執行緒間通訊

1)說明

    所謂執行緒間通訊,即如何從一個執行緒進入到另一個執行緒繼續執行任務或者是傳遞引數(如從子執行緒回到主執行緒)

    下面的程式碼示例演示在主執行緒中先建立一個子執行緒下載圖片,當圖片下載完成後又切換到主執行緒設定圖片的操作。

複製程式碼
 1 //!!!注意,該案例內部下載圖片,傳送了http請求需要修改info.plist檔案
 2     class ViewController: UIViewController {
 3 
 4     @IBOutlet weak var imageView: UIImageView!
 5 
 6     override func viewDidLoad() {
 7         super.viewDidLoad()
 8 
 9         //程式啟動後開子執行緒下載圖片,圖片下載完成之後回到主執行緒設定圖片
10          NSThread.detachNewThreadSelector(Selector("downloadImage"), toTarget: self, withObject: nil)
11     }
12 
13     func downloadImage()
14     {
15         //1.獲得要下載圖片的url
16         let url = NSURL.init(string: "http://p9.qhimg.com/t014d1bd470cb60ac6e.jpg")
17 
18         //2.把url地址指向資源的二進位制下載到本地
19         let imageData = NSData.init(contentsOfURL: url!)
20 
21         //3.把二進位制資料轉換為圖片
22         let image = UIImage.init(data: imageData!);
23 
24         //4.列印檢視當前執行緒(應該是在子執行緒中下載圖片)
25         print("當前執行緒為\(NSThread.currentThread())")
26 
27         //5.執行緒間通訊
28         //方法一
29         self.performSelectorOnMainThread(Selector("showImage:"), withObject: image, waitUntilDone:true)
30         //方法二
31         //imageView.performSelectorOnMainThread(Selector("setImage:"), withObject: image, waitUntilDone:true)
32     }
33 
34     
35     func showImage(image:UIImage)
36     {
37         //設定圖片
38         imageView.image = image
39 
40         //列印檢視設定圖片操作的執行緒
41         print("處理UI重新整理操作的執行緒\(NSThread.currentThread())")
42 
43     }
44 }
複製程式碼