iOS 多線程學習筆記 —— NSThread

本文複製、參考自文章:iOS多線程編程之NSThread的使用  ,主要爲了增強我的對知識的理解和記憶,不作他用。原做者聲明:html

著做權聲明:本文由http://blog.csdn.net/totogo2010/原創,歡迎轉載分享。請尊重做者勞動,轉載時保留該聲明和做者博客連接,謝謝!ios

這裏對原做者的辛勤工做表示感謝!編程

1. 簡介

1.1 iOS的多線程編程技術分類

(1)NSThread 數據結構

  (2) Cocoa NSOperation多線程

  (3) GCD (Grand Central Dispatch)app

這三種方式從上到下,抽象層次逐漸增高,使用也愈來愈簡單。異步

1.2 三種方式的優缺點

  優勢   缺點
NSThread 輕量 須要本身管理線程的生命週期,線程同步。線程同步加鎖時,會有必定的系統開銷。
NSOperation   無需關心線程管理,數據同步,能夠把精力放在本身須要的執行操做上  
GCD iOS4.0後出現,以替代NSThread,NSOperation等技術的,很高效、強大  

 

 

 

 

 

 

2. NSThread的使用

2.1 建立方式

(1) 實例方法建立測試

- (id) initWithTarget:(id)target selector:(SEL)selector object:(id) argument
示例: NSThread
* myThread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomething:) object:nil]; [myThread start];

  (2) NSThread 類方法建立url

+ (void)detachNewThreadSelector:(SEL) aSelector toTarget:(id)aTarget withObject:(id)anArgument

示例:
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:nil];

(3)NSObject 非顯示方法建立spa

+ (void) performSelectorInBackground:(SEL)aSelector withObject:(id)anArgument
示例
[Obj performSelectorInBackground:@selector(doSomething:)withObject:nil];

selector: 線程執行的方法,這個selector只能有一個參數,並且不能有返回值;

target:    selector消息發送的對象

argument:傳輸給selector的惟一參數,也能夠是nil

第一種方式會直接建立線程而且開始運行線程,第二種方法是先建立線程對象,而後再運行線程操做,在運行線程操做前能夠設置線程的優先級等線程信息。

 2.2 使用示例1: 異步加載圖片

(1)在viewDidLoad中建立子線程:

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSThread* thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:kURL]; // 子線程執行方法 downloadImage
    [thread start]; // 啓用子線程
}

(2)在線程執行方法 downloadImage 中執行加載數據操做,並使用performSelectorOnMainThread方法 通知主線程進行渲染操做。(線程調回主線程,並傳遞了數據)

- (void)downloadImage:(NSString *) url
{
    NSData* data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
    UIImage* image = [[UIImage alloc] initWithData:data];
    if(image == nil)
    {
        NSLog(@"image load failed...");
    }
    else
    {
        [self performSelectorOnMainThread:@selector(updateUI:) withObject:image waitUntilDone:YES]; // 與主線程通訊,傳遞了image數據
    }
}

  一樣,還可使用:  

- (void)performSelector:(SEL)aSelector  onThread:(NSThread *)thread   withObject:(id)arg    waitUntilDone:(BOOL)wait    modes:(NSArray *)array

方法來於其餘線程通訊。

2.3 使用示例2: 多線程賣票

 (1) 定義public的數據結構,AppDelegate.h中

@interface AppDelegate : UIResponder <UIApplicationDelegate>
{
    int tickets;
    int count;
    NSThread* ticketsThreadOne;
    NSThread* ticketsThreadTwo;
    NSCondition* ticketsCondition; 
    NSLock* theLock;
}

這裏測試使用了NSCondition和NSLock兩種加鎖方法。

(2)初始化, AppDelegate.m中

    tickets = 100;
    count = 0;
    theLock = [[NSLock alloc] init];
    // 鎖對象
    ticketsCondition = [[NSCondition alloc] init];
    ticketsThreadOne = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [ticketsThreadOne setName:@"Thread-1"];
    [ticketsThreadOne start];
    
    ticketsThreadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [ticketsThreadTwo setName:@"Thread-2"];
    [ticketsThreadTwo start];

(3)執行操做中,加鎖,防止資源搶佔

- (void)run
{
    while (TRUE)
    {
        // 上鎖
//        [theLock lock];
        [ticketsCondition lock];
        if (tickets >= 0)
        {
            [NSThread sleepForTimeInterval:0.09];
            count = 100 -tickets;
            NSLog(@"當前票數是:%d, 售出:%d, 線程名:%@", tickets, count, [[NSThread currentThread] name]);
            tickets--;
        }
        else
        {
            break;
        }
        [ticketsCondition unlock];
//        [theLock unlock];
    }
}

   NSCondition 可使用 [ticketsCondition wait];等待,並由其餘線程使用[ticketsCondition signal];喚起等待。

2.4 使用@synchoronized

  咱們還可使用@synchoronized來簡化NSLock的使用,這樣就沒必要顯示建立和調用NSLock對象,而自動建立了一個互斥鎖(mutex lock),防止對資源的搶佔。 以下

  

    obj1 = [[NSObject alloc]init]; // 兩個線程,分別傳遞兩個對象用於原操做標識
    obj2 = [[NSObject alloc]init];
    
    ticketsThreadOne = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:obj1]; 
    [ticketsThreadOne setName:@"Thread-1"];
    [ticketsThreadOne start];
    
    ticketsThreadTwo = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:obj2];
    [ticketsThreadTwo setName:@"Thread-2"];
    [ticketsThreadTwo start];
- (void)run:(NSObject*) obj
{
    @synchronized(obj)
    {
        while (TRUE)
        {
            // 上鎖
    //        [theLock lock];
    //        [ticketsCondition lock];
            int currentTicketNum = [ticketCounter currentTicketNum];
            if ( currentTicketNum >= 0)
            {
                [NSThread sleepForTimeInterval:0.09];
                NSLog(@"當前票數是:%d, 售出:%d, 線程名:%@", currentTicketNum, ticketCounter.initTicketNum - currentTicketNum, [[NSThread currentThread] name]);
                ticketCounter.currentTicketNum--;
            }
            else
            {
                break;
            }
    //        [ticketsCondition unlock];
    //        [theLock unlock];
        }
    }
}
相關文章
相關標籤/搜索