這篇博客是接着總篇iOS GCD NSOperation NSThread等多線程各種舉例詳解寫的一個支篇。總篇也包含了此文的鏈接。本文講解的知識點有NSThread的開始、取消、在當前線程執行任務、線程通信、線程同步、延時函數等。附上:demo下載地址。
一、NSThread介紹
優點:NSThread 比其他兩個輕量級。
缺點:需要自己管理線程的生命周期,線程同步。線程同步對數據的加鎖會有一定的系統開銷。
二、開始和取消
舉個例子,注釋寫的很詳細,不多說啦。
//開始 - (IBAction)start:(id)sender { //實例方法開始 _myThread = [[NSThread alloc]initWithTarget:self selector:@selector(startCount) object:nil]; [_myThread start]; //靜態方法開始 // [NSThread detachNewThreadSelector:@selector(startCount) toTarget:self withObject:nil]; //隱式開始 // [self performSelectorInBackground:@selector(startCount) withObject:nil]; } //計時 -(void)startCount { for (NSInteger i = 0; i< 1000; i++) { //根據線程是否取消的標志位退出該任務 if (_myThread.cancelled) { return; } [NSThread sleepForTimeInterval:1.0f]; NSLog(@"%ld",i); } } //取消線程 - (IBAction)cancel:(id)sender { //並沒有真正取消該線程,只是給該線程設置了一個標志位 [_myThread cancel]; }
注意:[_myThread cancel];並沒有取消該線程,只是給該線程設置了一個標志位,需要到具體任務里根據線程的.cancelled屬性判斷來取消。
三、線程通信
開一個子線程執行某任務,完成后回到主線程更新UI,實現線程通信,舉個例子。
//線程通信 - (IBAction)communication:(id)sender { //開一個子線程執行某任務,完成后回到主線程更新UI,實現線程通信 [NSThread detachNewThreadSelector:@selector(communicationTask) toTarget:self withObject:nil]; } //線程通信任務 - (void)communicationTask { NSLog(@"當前線程%@",[NSThread currentThread]); //模擬一個3秒的任務,完成后到主線程更新UI [NSThread sleepForTimeInterval:3]; [self performSelectorOnMainThread:@selector(updateUI:) withObject:[UIColor redColor] waitUntilDone:YES]; } //更新UI - (void)updateUI:(UIColor *)color { self.view.backgroundColor = color; NSLog(@"我變紅了%@",[NSThread currentThread]); }
打印結果:
分析結論:從communicationTask所在線程回到主線程更新了UI,實現了線程間通信。
四、線程同步
舉一個經典的搶票的例子。搶票涉及到多個線程對同一個數據進行操作,NSThread是要自己管理線程同步的,讓同一個時間只有一個線程操作該數據,那么我們就要用到加鎖。
@interface NSThreadViewController () { NSInteger tickets;//剩余票數 NSInteger sellNum;//賣出票數 NSThread* thread1;//買票線程1 NSThread* thread2;//買票線程2 NSLock *theLock;//鎖 } @property (nonatomic, strong) NSThread* myThread; @end
//(線程同步)2人搶票 - (IBAction)twoPeopleBuy:(id)sender { tickets = 9; sellNum = 0; theLock = [[NSLock alloc] init]; thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(buy) object:nil]; [thread1 setName:@"Thread-1"]; [thread1 start]; thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(buy) object:nil]; [thread2 setName:@"Thread-2"]; [thread2 start]; } //買票 -(void)buy{ while (TRUE) { //上鎖 [theLock lock]; if(tickets >= 0){ [NSThread sleepForTimeInterval:0.09]; sellNum = 9 - tickets; NSLog(@"當前票數是:%ld,售出:%ld,線程名:%@",tickets,sellNum,[[NSThread currentThread] name]); tickets--; }else{ break; } [theLock unlock]; } }
打印結果:
分析結論:加鎖來實現線程同步后,票是一張一張賣出去的。當把鎖去掉就會出現如下局面:
兩個線程同時操作一個數據,最后出現了負數。
五、NSThread延時
此方式在主線程和子線程中均可執行。是一種阻塞的執行方式,建方放到子線程中,以免卡住界面,沒有找到取消執行的方法。
[NSThread sleepForTimeInterval:3];//延時當前線程