最近兩年多一直在忙著做項(xiàng)目精绎,忽略了很多項(xiàng)目中常用的東西,這段時(shí)間得閑難得把一些東西總結(jié)一下畅涂,也是為了方便自己今后查看宛琅,這篇來談?wù)勅N多線程之一 NSThread
雖然不是最常用的但了解了解終歸是好的
NSThread
作為三種多線程之一,他是最輕量級(jí)的蒋腮,線程的聲明的生命周期都需要自己手動(dòng)管理淘捡,他的創(chuàng)建方法有三種第一種動(dòng)態(tài)創(chuàng)建
/**
* NSThread三種直接間接創(chuàng)建方法
* 第一種靜態(tài)動(dòng)態(tài)創(chuàng)建方法
* selector最多只能接收一個(gè)參數(shù)
*/
NSThread *thread_1 = [[NSThread alloc] initWithTarget:self selector:@selector(thread1) object:nil];
thread_1.name = @"thread_1";
[thread_1 start];
這種方法需要手動(dòng)開啟線程,對(duì)應(yīng)的selector最多只能接收一個(gè)參數(shù)
第二種靜態(tài)創(chuàng)建
/**
* 第二種靜態(tài)創(chuàng)建方法
*
*/
[NSThread detachNewThreadSelector:@selector(thread2) toTarget:self withObject:nil];
這種方法創(chuàng)建即啟動(dòng)
第三種隱式創(chuàng)建
/**
* 第三種隱式創(chuàng)建方法
*
*/
[self performSelectorInBackground:@selector(thread3) withObject:nil];
這種方式還有很多方法稍后一一說明
多線程說白了就是為了讓我們的程序變的不是那么臃腫不卡頓而生池摧,為了替主線程分擔(dān)任務(wù)而存在焦除,當(dāng)我們不管什么操作都放在主線程中進(jìn)行的時(shí)候你會(huì)發(fā)現(xiàn)你的程序恍如一個(gè)遲暮老人一樣遲鈍
NSThread
有很多方法 我這里把常用的一一列出
//打印出當(dāng)前線程
NSLog(@"thread1 --- %@",[NSThread currentThread]);
//判斷當(dāng)前是否在多線程
NSLog(@"thread1 --- %d",[NSThread isMultiThreaded]);
//判斷當(dāng)前是否在主線程
NSLog(@"thread1 --- %d",[NSThread isMainThread]);
//讓當(dāng)前線程睡眠幾秒
[NSThread sleepForTimeInterval:3.];
//讓當(dāng)前線程沉睡到指定時(shí)間
NSDate *date = [NSDate dateWithTimeInterval:2 sinceDate:[NSDate date]];
[NSThread sleepUntilDate:date];
剛才說了隱式創(chuàng)建的時(shí)候他對(duì)應(yīng)的有多種方法,來看看有哪些
//回到主線程 執(zhí)行UI操作
[self performSelectorOnMainThread:@selector(doSomeThing) withObject:nil waitUntilDone:YES];
這個(gè)方法很常用作彤,因?yàn)槲覀円话阍谧泳€程中進(jìn)行數(shù)據(jù)請(qǐng)求處理等等膘魄,處理完之后都要更新界面的,這個(gè)操作就需要回到主線程中去操作了
//在指定線程中進(jìn)行某操作
[self performSelector:@selector(doSomeThing) onThread:thread_1 withObject:nil waitUntilDone:YES];
這個(gè)方法是當(dāng)我們需要將某個(gè)操作添加到某個(gè)線程中進(jìn)行的時(shí)候拿來用的竭讳。
NSThread
掌握這些最常用基本就夠用了
下面來討論一下線程鎖的一些東西创葡,我們用到多線程,那有關(guān)線程安全的問題就不能不考慮了绢慢,就比如一個(gè)很經(jīng)典的例子灿渴,售票系統(tǒng),有多個(gè)窗口同時(shí)售票這就是一個(gè)多線程胰舆,他們同時(shí)訪問票務(wù)系統(tǒng)各自獨(dú)立骚露,這就導(dǎo)致了資源爭奪的現(xiàn)象,可能A窗口在訪問一塊資源的時(shí)候缚窿,B窗口也在訪問同一塊資源棘幸,這就出現(xiàn)了這塊資源到底給誰的問題,所以我們需要在A訪問的時(shí)候把資源加鎖滨攻,B只有等待A訪問完了才能訪問
關(guān)于線程鎖我這里說最常用的三個(gè)
@synchronized(self) {}
NSLock
NSCondition
看到第一個(gè)是不是感覺很熟悉我們?cè)诙x屬性的時(shí)候?qū)傩杂袀€(gè)修飾符叫atomic
也叫原子性 加了這個(gè)屬性就相當(dāng)于把屬性的setter方法里添加了@synchronized(self) {}
來保證安全够话,其實(shí)嚴(yán)格上講他并不是安全的蓝翰,這里隨便說一種
當(dāng)線程A光绕,在setter方法里給屬性設(shè)置值得時(shí)候,此時(shí)B線程在讀屬性的值畜份,因?yàn)閟etter和getter方法是沒有聯(lián)系的诞帐,這時(shí),A在執(zhí)行到加鎖爆雹,只是還沒有設(shè)置值停蕉,然而B線程已經(jīng)讀取走了愕鼓,本來是想讀取A設(shè)置之后的值,卻讀取了設(shè)置之前的值慧起,也就線程不安全了菇晃。
但是如果上面的AB線程都使用了同一把鎖,對(duì)相應(yīng)代碼進(jìn)行加鎖蚓挤,所以鎖內(nèi)的代碼是線程安全的磺送。所謂使用同一把鎖就是@synchronized() {}
()中的對(duì)象是同一個(gè)
在這三種加鎖方法中這一種是效率性能最低的
再來看第二個(gè)NSLock
//第二種
NSLock *lock = [[NSLock alloc] init];
[lock lock];
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[lock unlock];
這里加鎖的部分是lock塊里面的部分,這里可以防止不同的線程同時(shí)走這個(gè)方法的時(shí)候?qū)賦值出現(xiàn)沖突灿意,在線程A賦值的時(shí)候估灿,線程B也緊隨其后,原本外界需要的是A賦的值可事與愿違拿到了B賦的值缤剧,所以加鎖可以很有效的杜絕這種事情的發(fā)生A執(zhí)行的時(shí)候加上鎖B只能在外面等著A執(zhí)行完
第三種NSCondition
//第三種
NSCondition *condition = [[NSCondition alloc] init];
[condition lock];
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[condition unlock];
他也叫條件鎖這個(gè)用起來稍微麻煩點(diǎn)馅袁,可以直接用上面的方法像NSLock一樣用 也可以像下面一樣 判斷是否達(dá)到加鎖條件之后再加鎖
//第三種
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:1];
BOOL canLock = [conditionLock tryLockWhenCondition:1];
if (canLock) {
n = arc4random()%100;
NSLog(@"%ld",(long)n);
[conditionLock unlock];
}
數(shù)字1就是他的判斷條件,在外界可以定義幾個(gè)宏荒辕,來作為判斷條件汗销,這里就不贅述了
這三種加鎖方法如果不考慮性能的話第一種是不錯(cuò)的選擇,如果考慮性能的話第二第三都可以兄纺,不過他們都不是性能最好的
還有一些別的加鎖方法不過不常用大溜,掌握這三個(gè)就已經(jīng)夠用了.
這些只是本人的一些見解有不對(duì)的地方歡迎指出,作者也是個(gè)奮斗在前線的coder估脆,記錄這些也是想加深自己對(duì)此的理解
下一篇來探究三種多線程中的下一種