iOS開發 多線程(二) NSThread的使用(轉)

每一個iOS應用程序都有個專門用來更新顯示UI界面、處理用戶的觸摸事件的主線程,所以不能將其餘太耗時的操做放在主線程中執行,否則會形成主線程堵塞(出現卡機現象),帶來極壞的用戶體驗。通常的解決方案就是將那些耗時的操做放到另一個線程中去執行,多線程編程是防止主線程堵塞,增長運行效率的最佳方法java

iOS支持多個層次的多線程編程,層次越高的抽象程度越高,使用也越方便,也是蘋果最推薦使用的方法。下面根據抽象層次從低到高依次列出iOS所支持的多線程編程方法:編程

1.Thread :是三種方法裏面相對輕量級的,但須要管理線程的生命週期、同步、加鎖問題,這會致使必定的性能開銷
2.Cocoa Operations:是基於OC實現的,NSOperation以面向對象的方式封裝了須要執行的操做,沒必要關心線程管理、同步等問題。NSOperation是一個抽象基類,iOS提供了兩種默認實現:NSInvocationOperation和NSBlockOperation,固然也能夠自定義NSOperation
3.Grand Central Dispatch(簡稱GCD,iOS4纔開始支持):提供了一些新特性、運行庫來支持多核並行編程,它的關注點更高:如何在多個cpu上提高效率
多線程


這篇文章簡單介紹了第一種多線程編程的方式,主要是利用NSThread這個類,一個NSThread實例表明着一條線程app

1、NSthread的初始化ide

1.動態方法性能

[java] view plaincopyatom

  1. - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument;  spa

[java] view plaincopy.net

  1. // 初始化線程  線程

  2. NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  3. // 設置線程的優先級(0.0 - 1.0,1.0最高級)  

  4. thread.threadPriority = 1;  

  5. // 開啓線程  

  6. [thread start];  

參數解析:

selector :線程執行的方法,這個selector最多隻能接收一個參數
target :selector消息發送的對象
argument : 傳給selector的惟一參數,也能夠是nil


2.靜態方法

[java] view plaincopy

  1. + (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;  

[java] view plaincopy

  1. [NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];  

  2. // 調用完畢後,會立刻建立並開啓新線程  


3.隱式建立線程的方法

[java] view plaincopy

  1. [self performSelectorInBackground:@selector(run) withObject:nil];  


2、獲取當前線程

[java] view plaincopy

  1. NSThread *current = [NSThread currentThread];  


3、獲取主線程

[java] view plaincopy

  1. NSThread *main = [NSThread mainThread];  


4、暫停當前線程

[java] view plaincopy

  1. // 暫停2s  

  2. [NSThread sleepForTimeInterval:2];  

  3.   

  4. // 或者  

  5. NSDate *date = [NSDate dateWithTimeInterval:2 sinceDate:[NSDate date]];  

  6. [NSThread sleepUntilDate:date];  


5、線程間的通訊

1.在指定線程上執行操做

[java] view plaincopy

  1. [self performSelector:@selector(run) onThread:thread withObject:nil waitUntilDone:YES];  


2.在主線程上執行操做

[java] view plaincopy

  1. [self performSelectorOnMainThread:@selector(run) withObject:nil waitUntilDone:YES];  


3.在當前線程執行操做

[java] view plaincopy

  1. [self performSelector:@selector(run) withObject:nil];  


6、優缺點

1.優勢:NSThread比其餘兩種多線程方案較輕量級,更直觀地控制線程對象

2.缺點:須要本身管理線程的生命週期,線程同步。線程同步對數據的加鎖會有必定的系統開銷

--------------------------------------------

--------------另一個博客的補充----------

2.3 線程同步

咱們演示一個經典的賣票的例子來說NSThread的線程同步:

.h

[cpp] view plaincopy

  1. #import <UIKit/UIKit.h>  

  2.   

  3. @class ViewController;  

  4.   

  5. @interface AppDelegate : UIResponder <UIApplicationDelegate>  

  6. {  

  7.     int tickets;  

  8.     int count;  

  9.     NSThread* ticketsThreadone;  

  10.     NSThread* ticketsThreadtwo;  

  11.     NSCondition* ticketsCondition;  

  12.     NSLock *theLock;  

  13. }  

  14. @property (strong, nonatomic) UIWindow *window;  

  15.   

  16. @property (strong, nonatomic) ViewController *viewController;  

  17.   

  18. @end  

[cpp] view plaincopy

  1. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

  2. {  

  3.       

  4.     tickets = 100;  

  5.     count = 0;  

  6.     theLock = [[NSLock alloc] init];  

  7.     // 鎖對象  

  8.     ticketsCondition = [[NSCondition alloc] init];  

  9.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  10.     [ticketsThreadone setName:@"Thread-1"];  

  11.     [ticketsThreadone start];  

  12.       

  13.       

  14.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  15.     [ticketsThreadtwo setName:@"Thread-2"];  

  16.     [ticketsThreadtwo start];  

  17.       

  18.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  

  19.     // Override point for customization after application launch.  

  20.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  

  21.     self.window.rootViewController = self.viewController;  

  22.     [self.window makeKeyAndVisible];  

  23.     return YES;  

  24. }  

  25.   

  26. - (void)run{  

  27.     while (TRUE) {  

  28.         // 上鎖  

  29. //        [ticketsCondition lock];  

  30.         [theLock lock];  

  31.         if(tickets >= 0){  

  32.             [NSThread sleepForTimeInterval:0.09];  

  33.             count = 100 - tickets;  

  34.             NSLog(@"當前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);  

  35.             tickets--;  

  36.         }else{  

  37.             break;  

  38.         }  

  39.         [theLock unlock];  

  40. //        [ticketsCondition unlock];  

  41.     }  

  42. }  

若是沒有線程同步的lock,賣票數多是-1.加上lock以後線程同步保證了數據的正確性。
上面例子我使用了兩種鎖,一種NSCondition ,一種是:NSLock。 NSCondition我已經註釋了。

線程的順序執行

他們均可以經過

        [ticketsCondition signal]; 發送信號的方式,在一個線程喚醒另一個線程的等待。

好比:

[cpp] view plaincopy

  1. #import "AppDelegate.h"  

  2.   

  3. #import "ViewController.h"  

  4.   

  5. @implementation AppDelegate  

  6.   

  7. - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions  

  8. {  

  9.       

  10.     tickets = 100;  

  11.     count = 0;  

  12.     theLock = [[NSLock alloc] init];  

  13.     // 鎖對象  

  14.     ticketsCondition = [[NSCondition alloc] init];  

  15.     ticketsThreadone = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  16.     [ticketsThreadone setName:@"Thread-1"];  

  17.     [ticketsThreadone start];  

  18.       

  19.     ticketsThreadtwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];  

  20.     [ticketsThreadtwo setName:@"Thread-2"];  

  21.     [ticketsThreadtwo start];  

  22.       

  23.     NSThread *ticketsThreadthree = [[NSThread alloc] initWithTarget:self selector:@selector(run3) object:nil];  

  24.     [ticketsThreadthree setName:@"Thread-3"];  

  25.     [ticketsThreadthree start];      

  26.     self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];  

  27.     // Override point for customization after application launch.  

  28.     self.viewController = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil];  

  29.     self.window.rootViewController = self.viewController;  

  30.     [self.window makeKeyAndVisible];  

  31.     return YES;  

  32. }  

  33.   

  34. -(void)run3{  

  35.     while (YES) {  

  36.         [ticketsCondition lock];  

  37.         [NSThread sleepForTimeInterval:3];  

  38.         [ticketsCondition signal];  

  39.         [ticketsCondition unlock];  

  40.     }  

  41. }  

  42.   

  43. - (void)run{  

  44.     while (TRUE) {  

  45.         // 上鎖  

  46.         [ticketsCondition lock];  

  47.         [ticketsCondition wait];  

  48.         [theLock lock];  

  49.         if(tickets >= 0){  

  50.             [NSThread sleepForTimeInterval:0.09];  

  51.             count = 100 - tickets;  

  52.             NSLog(@"當前票數是:%d,售出:%d,線程名:%@",tickets,count,[[NSThread currentThread] name]);  

  53.             tickets--;  

  54.         }else{  

  55.             break;  

  56.         }  

  57.         [theLock unlock];  

  58.         [ticketsCondition unlock];  

  59.     }  

  60. }  

wait是等待,我加了一個 線程3 去喚醒其餘兩個線程鎖中的wait

其餘同步

咱們可使用指令 @synchronized 來簡化 NSLock的使用,這樣咱們就沒必要顯示編寫建立NSLock,加鎖並解鎖相關代碼。- (void)doSomeThing:(id)anObj{    @synchronized(anObj)    {        // Everything between the braces is protected by the @synchronized directive.    }}

相關文章
相關標籤/搜索