iOS 多線程(I)

1. Objective-C 中創(chuàng)建線程的方法是什么?如果在主線程中執(zhí)行代碼驱负,方法是什么作箍?如果想延時執(zhí)行代碼、方法又是什么合武?

    線程創(chuàng)建有三種方法:使用NSThread創(chuàng)建临梗、使用GCD的dispatch、使用子類化的NSOperation,然后將其加入NSOperationQueue;在主線程執(zhí)行代碼稼跳。

    方法是performSelectorOnMainThread盟庞,如果想延時執(zhí)行代碼可以用performSelector:onThread:withObject:waitUntilDone:。



2. 有哪些對象和變量需要釋放掉汤善?

如:線程的queue什猖, 繪制圖片的上下文等;



3. RunLoop 的5種運行方式是什么红淡?

kCFRunLoopDefaultMode:  
UITrackingRunLoopMode:  
UIInitializationaRunLoopMode:  
GSEventReceiveRunLoopMode:  
KCFCommonRunLoopModes:  



4.我們說的OC是動態(tài)運行時語言是什么意思不狮?

主要是將數(shù)據(jù)類型的確定由編譯時,推遲到了運行時在旱。

簡單來說, 運行時機制使我們直到運行時才去決定一個對象的類別,以及調(diào)用該類別對象指定方法摇零。



5. GCD 與 NSOperation 的區(qū)別:

GCD 和 NSOperation 都是用于實現(xiàn)多線程:
    GCD 基于C語言的底層API,GCD主要與block結(jié)合使用桶蝎,代碼簡潔高效驻仅。
    NSOperation 屬于Objective-C類,是基于GCD更高一層的封裝登渣。復(fù)雜任務(wù)一般用NSOperation實現(xiàn)噪服。



6. 寫出使用GCD方式從子線程回到主線程的方法代碼

dispatch_sync(dispatch_get_main_queue(), ^{ });



7. 如何用GCD同步若干個異步調(diào)用?(如根據(jù)若干個url異步加載多張圖片胜茧,然后在都下載完成后合成一張整圖)

// 使用Dispatch Group追加block到Global Group Queue,這些block如果全部執(zhí)行完畢粘优,就會執(zhí)行Main Dispatch Queue中的結(jié)束處理的block。
// 創(chuàng)建隊列組
dispatch_group_t group = dispatch_group_create();
// 獲取全局并發(fā)隊列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_async(group, queue, ^{ /*加載圖片1 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片2 */ });
dispatch_group_async(group, queue, ^{ /*加載圖片3 */ }); 
// 當(dāng)并發(fā)隊列組中的任務(wù)執(zhí)行完畢后才會執(zhí)行這里的代碼
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        // 合并圖片
});



8. dispatch_barrier_async(柵欄函數(shù))的作用是什么竹揍?

函數(shù)定義:dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);
作用:
    1.在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行敬飒,它后面的任務(wù)要等它執(zhí)行完成后才會開始執(zhí)行。
    2.避免數(shù)據(jù)競爭

// 1.創(chuàng)建并發(fā)隊列
dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
// 2.向隊列中添加任務(wù)
dispatch_async(queue, ^{  // 1.2是并行的
    NSLog(@"任務(wù)1, %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"任務(wù)2, %@",[NSThread currentThread]);
});

dispatch_barrier_async(queue, ^{
    NSLog(@"任務(wù) barrier, %@", [NSThread currentThread]);
});

dispatch_async(queue, ^{   // 這兩個是同時執(zhí)行的
    NSLog(@"任務(wù)3, %@",[NSThread currentThread]);
});
dispatch_async(queue, ^{
    NSLog(@"任務(wù)4, %@",[NSThread currentThread]);
});

// 輸出結(jié)果: 任務(wù)1 任務(wù)2 ——》 任務(wù) barrier ——》任務(wù)3 任務(wù)4 
// 其中的任務(wù)1與任務(wù)2芬位,任務(wù)3與任務(wù)4 由于是并行處理先后順序不定无拗。

參考資料:GCD(III)



9. 以下代碼運行結(jié)果如何?

- (void)viewDidLoad {
    [super viewDidLoad];
    NSLog(@"1");
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"2");
    });
    NSLog(@"3");
}
// 只輸出:1昧碉。(主線程死鎖)



10. 什么是 RunLoop?

從字面上講就是運行循環(huán)英染,它內(nèi)部就是do-while循環(huán)揽惹,在這個循環(huán)內(nèi)部不斷地處理各種任務(wù)。
一個線程對應(yīng)一個RunLoop四康,基本作用就是保持程序的持續(xù)運行搪搏,處理app中的各種事件。通過runloop闪金,有事運行疯溺,沒事就休息,可以節(jié)省cpu資源哎垦,提高程序性能囱嫩。

主線程的run loop默認是啟動的。iOS的應(yīng)用程序里面漏设,程序啟動后會有一個如下的main()函數(shù)
int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

參考資料:RunLoop 詳細介紹



11. OC中創(chuàng)建線程的方法是什么墨闲?如果在主線程中執(zhí)行代碼,方法是什么郑口?

// 創(chuàng)建線程的方法
- [NSThread detachNewThreadSelector:nil toTarget:nil withObject:nil]
- [self performSelectorInBackground:nil withObject:nil];
- [[NSThread alloc] initWithTarget:nil selector:nil object:nil];
- dispatch_async(dispatch_get_global_queue(0, 0), ^{});
- [[NSOperationQueue new] addOperation:nil];

// 主線程中執(zhí)行代碼的方法
- [self performSelectorOnMainThread:(SEL)aSelector  withObject:nil waitUntilDone:YES];
- dispatch_async(dispatch_get_main_queue(), ^{});
- [[NSOperationQueue mainQueue] addOperation:nil];



12. 你用過NSOperationQueue么鸳碧?如果用過或者了解的話,你為什么要使用NSOperationQueue犬性,實現(xiàn)了什么瞻离?請描述它和G.C.D的區(qū)別和類似的地方(提示:可以從兩者的實現(xiàn)機制和適用范圍來描述)

使用NSOperationQueue用來管理子類化的NSOperation對象,控制
其線程并發(fā)數(shù)目仔夺。GCD和NSOperation都可以實現(xiàn)對線程的管理琐脏,區(qū)別
是 NSOperation和NSOperationQueue是多線程的面向?qū)ο蟪橄蟆m椖恐?使用NSOperation的優(yōu)點是NSOperation是對線程的高度抽象缸兔,在項目中
使用它日裙,會使項目的程序結(jié)構(gòu)更好,子類化NSOperation的設(shè)計思路惰蜜,
是具有面向?qū)ο蟮膬?yōu)點(復(fù)用昂拂、封裝),使得實現(xiàn)是多線程支持抛猖,而接
口簡單格侯,建議在復(fù)雜項目中使用。
項目中使用GCD的優(yōu)點是GCD本身非常簡單财著、易用联四,對于不復(fù)雜的多線
程操作,會節(jié)省代碼量撑教,而Block參數(shù)的使用朝墩,會是代碼更為易讀,建議
在簡單項目中使用伟姐。



13. iOS 的幾種線程鎖收苏?
互斥鎖:用于多線程編程亿卤,防止兩條線程同時對同一公共資源進行讀寫的機制;

@synchronized  簡單鹿霸、效率最低排吴。

NSLock  不能多次調(diào)用 lock方法,會造成死鎖;  

pthread_mutex



自旋鎖:采用信號的一種同步方式

dispatch_semaphore  使用信號量來獲取更多的取值空間懦鼠,用來實現(xiàn)更加復(fù)雜的同步钻哩,而不單單是線程間互斥;

OSSpinLock



遞歸鎖:同一個線程可以加鎖N次而不會引發(fā)死鎖

NSRecursiveLock



條件鎖: 條件變量葛闷,當(dāng)進程的某些資源要求不滿足時就進入休眠憋槐,也就是鎖住了。當(dāng)資源被分配到了淑趾,條件鎖打開,進程繼續(xù)運行

NSCondition

NSConditionLock

遵循NSLocking協(xié)議忧陪,使用的時候同樣是lock,unlock加解鎖扣泊,wait是傻等,waitUntilDate:方法是等一會嘶摊,都會阻塞掉線程延蟹,signal是喚起一個在等待的線程,broadcast是廣播全部喚起叶堆。



讀寫鎖

//加讀鎖
pthread_rwlock_rdlock(&rwlock);
//解鎖
pthread_rwlock_unlock(&rwlock);
//加寫鎖
pthread_rwlock_wrlock(&rwlock);
//解鎖
pthread_rwlock_unlock(&rwlock);



14. NSThread阱飘、NSOperationQueue、GCD 3種線程的認知

1)  NSThread 是這三種范式里面相對輕量級的虱颗,但也是使用起來最負責(zé)的沥匈,
你需要自己管理thread的生命周期,線程之間的同步忘渔。線程共享同一應(yīng)用程序的部分內(nèi)存空間高帖,
它們擁有對數(shù)據(jù)相同的訪問權(quán)限。你得協(xié)調(diào)多個線程對同一數(shù)據(jù)的訪問畦粮,
一般做法是在訪問之前加鎖散址,這會導(dǎo)致一定的性能開銷。

2)  NSOperationQueue 以面向?qū)ο蟮姆绞椒庋b了用戶需要執(zhí)行的操作宣赔,
我們只要聚焦于我們需要做的事情预麸,而不必太操心線程的管理,同步等事情儒将,
因為NSOperation已經(jīng)為我們封裝了這些事情吏祸。
NSOperation 是一個抽象基類,我們必須使用它的子類椅棺。

3)  GCD: iOS4 才開始支持犁罩,它提供了一些新的特性齐蔽,以及運行庫來支持多核并行編程,
它的關(guān)注點更高:如何在多個cpu上提升效率床估。

總結(jié):
- NSThread是早期的多線程解決方案含滴,實際上是把C語言的PThread線程管理代碼封裝成OC代碼。
- GCD是取代NSThread的多線程技術(shù)丐巫,C語法+block谈况。功能強大。
- NSOperationQueue是把GCD封裝為OC語法递胧,額外比GCD增加了幾項新功能碑韵。
    * 最大線程并發(fā)數(shù)
    * 取消隊列中的任務(wù)
    * 暫停隊列中的任務(wù)
    * 可以調(diào)整隊列中的任務(wù)執(zhí)行順序,通過優(yōu)先級
    * 線程依賴
    * NSOperationQueue支持KVO缎脾。這就意味著你可以觀察任務(wù)的狀態(tài)屬性祝闻。
但是NSOperationQueue的執(zhí)行效率沒有GCD高,所以一半情況下遗菠,我們使用GCD來完成多線程操作联喘。



15. 多個網(wǎng)絡(luò)請求完成后執(zhí)行下一步,有幾種解決方案辙纬?
使用dispatch_group

-(void)Btn2{
    NSString *str = @"http://www.reibang.com/p/6930f335adba";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];

    dispatch_group_t downloadGroup = dispatch_group_create();
    for (int i=0; i<10; i++) {
        dispatch_group_enter(downloadGroup);

        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

            NSLog(@"%d---%d",i,i);
            dispatch_group_leave(downloadGroup);

        }];

        [task resume];
    }

    dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
}

? 創(chuàng)建一個dispatch_group_t豁遭, 每次網(wǎng)絡(luò)請求前先dispatch_group_enter,請求回調(diào)后再dispatch_group_leave,對于enter和leave必須配合使用,有幾次enter就要有幾次leave贺拣,否則group會一直存在蓖谢。當(dāng)所有enter的block都leave后,會執(zhí)行dispatch_group_notify的block譬涡。



采用信號量dispatch_semaphore_t

-(void)Btn3{
    NSString *str = @"http://www.reibang.com/p/6930f335adba";
    NSURL *url = [NSURL URLWithString:str];
    NSURLRequest *request = [NSURLRequest requestWithURL:url];
    NSURLSession *session = [NSURLSession sharedSession];

    dispatch_semaphore_t sem = dispatch_semaphore_create(0);
    for (int i=0; i<10; i++) {

        NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {

            NSLog(@"%d---%d",i,i);
            count++;
            if (count==10) {
                dispatch_semaphore_signal(sem);
                count = 0;
            }

        }];

        [task resume];
    }
    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@"end");
    });
}

dispatch_semaphore信號量為基于計數(shù)器的一種多線程同步機制闪幽。如果semaphore計數(shù)大于等于1,計數(shù)-1昂儒,返回沟使,程序繼續(xù)運行。如果計數(shù)為0渊跋,則等待腊嗡。dispatch_semaphore_signal(semaphore)為計數(shù)+1操作,dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER)為設(shè)置等待時間,這里設(shè)置的等待時間是一直等待拾酝。
對于以上代碼通俗一點就是燕少,開始為0,等待蒿囤,等10個網(wǎng)絡(luò)請求都完成了客们,dispatch_semaphore_signal(semaphore)為計數(shù)+1,然后計數(shù)-1返回,程序繼續(xù)執(zhí)行底挫。(這里也就是為什么有個count變量的原因恒傻,記錄網(wǎng)絡(luò)回調(diào)的次數(shù),回調(diào)10次之后再發(fā)信號量建邓,使后面程序繼續(xù)運行)盈厘。



使用dispatch_barrier_async(柵欄函數(shù))

dispatch_barrier_sync(dispatch_queue_t   queue, ^{

    })
  • 在它前面的任務(wù)執(zhí)行結(jié)束后它才執(zhí)行,它后面的任務(wù)要等它執(zhí)行完成后才會開始執(zhí)行官边,

  • 避免數(shù)據(jù)競爭
    GCD(III)



15. OC 的鎖有哪些沸手?

@synchronized.                             加鎖的對象需要是同一個對象
NSLock 對象鎖。                           多次lock死鎖
NSRecursiveLock   遞歸鎖注簿。        場景限制
NSConditionLock   條件鎖契吉。
pthread_mutex (C語言)互斥鎖   linux 底層
dispatch_semaphore (GCD)。  信號量
OSSpinLock (不建議使用)



16. 自旋和互斥對比诡渴?

相同點:都能保證同一時間只有一個線程訪問共享資源捐晶。都能保證線程安全。

不同點: 

互斥鎖:如果共享數(shù)據(jù)已經(jīng)有其他線程加鎖了妄辩,線程會進入休眠狀態(tài)等待鎖租悄。一旦被訪問的資源被解鎖,則等待資源的線程會被喚醒恩袱。

自旋鎖:如果共享數(shù)據(jù)已經(jīng)有其他線程加鎖了,線程會以死循環(huán)的方式等待鎖胶哲,一旦被訪問的資源被解鎖畔塔,則等待資源的線程會立即執(zhí)行。

自旋鎖的效率高于互斥鎖鸯屿。



17. 使用以上鎖需要注意哪些澈吨?

使用自旋鎖時要注意:
  由于自旋時不釋放CPU,因而持有自旋鎖的線程應(yīng)該盡快釋放自旋鎖寄摆,否則等待該自旋鎖的線程會一直在哪里自旋谅辣,這就會浪費CPU時間。

  持有自旋鎖的線程在sleep之前應(yīng)該釋放自旋鎖以便其它線程可以獲得該自旋鎖婶恼。內(nèi)核編程中桑阶,如果持有自旋鎖的代碼sleep了就可能導(dǎo)致整個系統(tǒng)掛起。

  使用任何鎖都需要消耗系統(tǒng)資源(內(nèi)存資源和CPU時間)勾邦,這種資源消耗可以分為兩類:
        1.建立鎖所需要的資源

        2.當(dāng)線程被阻塞時所需要的資源

使用互斥鎖的注意:
  由于是互斥鎖蚣录,當(dāng)一個線程進行訪問的時候,該線程獲得鎖眷篇,其他線程進行訪問的時候萎河,將被操作系統(tǒng)掛起,直到該線程釋放鎖,其他線程才能對其進行訪問虐杯,從而卻確保了線程安全玛歌。但是如果連續(xù)鎖定兩次,則會造成死鎖問題擎椰。

 

兩種鎖的加鎖原理:

互斥鎖:線程會從sleep(加鎖)——>running(解鎖)支子,過程中有上下文的切換(主動出讓時間片,線程休眠确憨,等待下一次喚醒)译荞,cpu的搶占,信號的發(fā)送等開銷休弃。

自旋鎖:線程一直是running(加鎖——>解鎖)吞歼,死循環(huán)(忙等 do-while)檢測鎖的標志位,機制不復(fù)雜塔猾。



``




``




``




``




``




``


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末篙骡,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子丈甸,更是在濱河造成了極大的恐慌糯俗,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,561評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件睦擂,死亡現(xiàn)場離奇詭異得湘,居然都是意外死亡,警方通過查閱死者的電腦和手機顿仇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,218評論 3 385
  • 文/潘曉璐 我一進店門淘正,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人臼闻,你說我怎么就攤上這事鸿吆。” “怎么了述呐?”我有些...
    開封第一講書人閱讀 157,162評論 0 348
  • 文/不壞的土叔 我叫張陵惩淳,是天一觀的道長。 經(jīng)常有香客問我乓搬,道長思犁,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,470評論 1 283
  • 正文 為了忘掉前任缤谎,我火速辦了婚禮抒倚,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘坷澡。我一直安慰自己托呕,他們只是感情好含蓉,可當(dāng)我...
    茶點故事閱讀 65,550評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著项郊,像睡著了一般馅扣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上着降,一...
    開封第一講書人閱讀 49,806評論 1 290
  • 那天差油,我揣著相機與錄音,去河邊找鬼任洞。 笑死蓄喇,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的交掏。 我是一名探鬼主播妆偏,決...
    沈念sama閱讀 38,951評論 3 407
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼盅弛!你這毒婦竟也來了钱骂?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,712評論 0 266
  • 序言:老撾萬榮一對情侶失蹤挪鹏,失蹤者是張志新(化名)和其女友劉穎见秽,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體讨盒,經(jīng)...
    沈念sama閱讀 44,166評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡解取,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,510評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了返顺。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肮蛹。...
    茶點故事閱讀 38,643評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖创南,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情省核,我是刑警寧澤稿辙,帶...
    沈念sama閱讀 34,306評論 4 330
  • 正文 年R本政府宣布,位于F島的核電站气忠,受9級特大地震影響邻储,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旧噪,卻給世界環(huán)境...
    茶點故事閱讀 39,930評論 3 313
  • 文/蒙蒙 一吨娜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧淘钟,春花似錦宦赠、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,745評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽毡琉。三九已至,卻和暖如春妙色,著一層夾襖步出監(jiān)牢的瞬間桅滋,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,983評論 1 266
  • 我被黑心中介騙來泰國打工身辨, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留丐谋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,351評論 2 360
  • 正文 我出身青樓煌珊,卻偏偏與公主長得像号俐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子怪瓶,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,509評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 29,338評論 8 265
  • Object C中創(chuàng)建線程的方法是什么萧落?如果在主線程中執(zhí)行代碼,方法是什么洗贰?如果想延時執(zhí)行代碼找岖、方法又是什么? 1...
    AlanGe閱讀 1,721評論 0 17
  • 原文地址 http://www.cnblogs.com/kenshincui/p/3983982.html 大家都...
    怎樣m閱讀 1,266評論 0 1
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,092評論 1 32
  • 1.進程 系統(tǒng)中正在運行的應(yīng)用程序每個進程之間是相互獨立的敛滋,運行在各自獨有且受保護的內(nèi)存中 2.線程 1.進程是不...
    GSChan閱讀 369評論 0 2