多線程

主要內(nèi)容:
1 GCD隊(duì)列循環(huán)等待、多讀單寫(xiě)、組任務(wù)
2 NSOpertaion優(yōu)點(diǎn)
3 NSThread實(shí)現(xiàn)原理
4 常用鎖的區(qū)別

GCD

同步串行

在viewDidLoad中有下面一段代碼

 dispatch_sync(dispatch_get_main_queue(), ^{
        [self doSomething];
   });

很多人說(shuō)這會(huì)造成死鎖。其實(shí)更準(zhǔn)確的說(shuō)法是:主隊(duì)列循環(huán)等待造成死鎖。


主隊(duì)列

主隊(duì)列是一個(gè)串行隊(duì)列,viewDidLoad提交到了主線程執(zhí)還未執(zhí)行完畢,此時(shí)再同步提交doSomething到主線程。viewDidLoad被阻塞等待doSomething返回,而doSomething是后提交的任務(wù),必須等前一個(gè)任務(wù)viewDidLoad執(zhí)行完畢后,才能執(zhí)行。這就是隊(duì)列循環(huán)等待造成的死鎖。
在viewDidLoad中代碼改為如下

_serialQueue = dispatch_queue_create("thread_name", DISPATCH_QUEUE_SERIAL);
dispatch_sync(_serialQueue, ^{
        [self doSomething];
 });

這樣會(huì)不會(huì)造成,隊(duì)列循環(huán)等待呢?答案是:不會(huì)。



這里需要注意:只要是同步方式提交,不管是提交到串行隊(duì)列還是并發(fā)隊(duì)列,都是在當(dāng)前線程執(zhí)行。
所以,如圖所示不會(huì)造成死鎖,并且doSomething會(huì)在主線程中執(zhí)行。

同步提交到并發(fā)隊(duì)列

NSLog(@"1");
dispatch_sync(globalQueue, ^{
        NSLog(@"2");
        dispatch_sync(globalQueue, ^{
            NSLog(@"3");
        });
         NSLog(@"4");
  });
  NSLog(@"5");

并發(fā)隊(duì)列特點(diǎn):提交到隊(duì)列的block可以并發(fā)執(zhí)行。 打印結(jié)果12345

異步提交到并發(fā)隊(duì)列

 dispatch_async(dispatch_get_global_queue(0, 0), ^{
      NSLog(@"1");
      [self performSelector:@selector(printLog) withObject:nil afterDelay:0];
       NSLog(@"3");
 });
-(void)printLog
{
    NSLog(@"2");
}

結(jié)果是:1和3。RunLoop在主線程是自動(dòng)創(chuàng)建的,在子線程中是沒(méi)有創(chuàng)建的。performSelector:withObject:afterDelay: 方法關(guān)鍵是afterDelay相當(dāng)于創(chuàng)建了一個(gè)Timer提交到了RunLoop。等待下一次RunLoop循環(huán)事件時(shí)執(zhí)行。而子線程中RunLoop根本就沒(méi)有創(chuàng)建。所以printLog也就不會(huì)執(zhí)行。

[self performSelector:@selector(printLog) withObject:nil];
[self performSelectorOnMainThread:@selector(printLog) withObject:nil waitUntilDone:YES];

請(qǐng)注意上面2個(gè)方法就是一個(gè)普通方法調(diào)用。與帶afterDelay的有本質(zhì)區(qū)別。

dispatch_barrier_async()

提供了一種多讀單寫(xiě)技術(shù),讀與讀可以并發(fā),讀與寫(xiě)是互斥的,寫(xiě)和寫(xiě)之間是互斥的。


#import "DataCenter.h"

@interface  DataCenter()
{
    dispatch_queue_t  _concurrent_queue;
    //用戶數(shù)據(jù)中心,可能有多個(gè)線程需要訪問(wèn)
    NSMutableDictionary *_dataCenterDict;
}

@end

@implementation DataCenter

-(id)init
{
    self = [super init];
    if(self){
        _concurrent_queue = dispatch_queue_create("read_write_queue", DISPATCH_QUEUE_CONCURRENT);
        _dataCenterDict = [NSMutableDictionary dictionary];
    }
    return self;
}

-(id)objectForKey:(NSString*)key
{
    __block id obj;
    //同步讀取指定數(shù)據(jù): 若果是線程A調(diào)用,那么子啊線程A中執(zhí)行。 若果是線程B調(diào)用,那么在線程B中執(zhí)行
    //由于是并發(fā)隊(duì)列,可以同時(shí)滿足多個(gè)線程同時(shí)調(diào)用。
    dispatch_sync(_concurrent_queue, ^{
        obj = [_dataCenterDict objectForKey:key];
    });
    return obj;
}

-(void)setObject:(id)obj forKey:(NSString*)key
{
    //異步調(diào)用柵欄設(shè)置數(shù)據(jù)
    dispatch_barrier_async(_concurrent_queue, ^{
        [_dataCenterDict setObject:obj forKey:key];
    });
}

NSOperation

優(yōu)點(diǎn)
1 添加依賴任務(wù)
2 任務(wù)執(zhí)行狀態(tài)控制
3 控制最大并發(fā)量

任務(wù)執(zhí)行狀態(tài)控制
isReady : 就緒
isExecuting: 執(zhí)行中
isFinished: 執(zhí)行完成
isCancelled: 已取消
只重寫(xiě)main()方法,系統(tǒng)控制任務(wù)狀態(tài),以及退出
重寫(xiě)了start()方法,需要自己控制任務(wù)狀態(tài)
系統(tǒng)是怎樣移除一個(gè)isFinished=YES的NSOperation的?KVO

NSThread

實(shí)現(xiàn)原理:內(nèi)部創(chuàng)建了一個(gè)pthread線程,當(dāng)執(zhí)行完main函數(shù)后,系統(tǒng)會(huì)自動(dòng)退出。


@synchronized

一般在創(chuàng)建單例對(duì)象的時(shí)候使用,保證在多線程環(huán)境下創(chuàng)建對(duì)象唯一

atomic

屬性關(guān)鍵字,對(duì)被修飾對(duì)象進(jìn)行原子操作(不負(fù)責(zé)使用)

@property(atomic)NSMutableArray *array;
self.array = [NSMutableArray array]; //保證線程安全
[self.array addObject: obj]; //不保證線程安全
OSSpinLock

循環(huán)等待訪問(wèn),不釋放當(dāng)前資源, 專門(mén)用于輕量級(jí)訪問(wèn),如+1,-1操作。如:引用計(jì)數(shù)

NSRecursiveLock

遞歸鎖可以重入

NSLock

互斥鎖,不可重入,上鎖解鎖,成對(duì)出現(xiàn)。

dispatch_semaphore_t
dispatch_semaphore_create(1);
dispatch_semaphore_wait(semphore,DISPATCH_TIME_FOREVER);
dispatch_semaphore_signal(semaphore)
dispatch_semaphore_create()
struct semaphore {
    int value;
    List<thread> //相關(guān)線程
}

dispatch_semaphore_wait 檢測(cè)到S.value < 0 ,主動(dòng)阻塞自己

dispatch_semaphore_wait()
{
    S.value = S.value - 1;
    if S.value < 0  then Block(S.List);  
}

dispatch_semaphore_signal 檢查后,去喚醒線程。對(duì)于線程來(lái)說(shuō),是一個(gè)被動(dòng)喚醒。

dispatch_semaphore_signal()
{
    S.value = S.value + 1;
    if(S.value <= 0) then wakeup(S.List)
}

總結(jié)

1 怎樣GCD實(shí)現(xiàn)多讀單寫(xiě)?
2 iOS提供了幾種多線程技術(shù),各自特點(diǎn)是什么?
3 NSOpertaion對(duì)象在Finished之后是怎樣從queue當(dāng)中移除的?
4 你多用過(guò)那些鎖?結(jié)合實(shí)際談?wù)勀闶窃鯓訉?shí)現(xiàn)的?

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 從哪說(shuō)起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個(gè)最簡(jiǎn)單的問(wèn)題,以這個(gè)作為切入點(diǎn)好了 在ma...
    Mr_Baymax閱讀 2,912評(píng)論 1 17
  • GCD簡(jiǎn)介 GCD 是 libdispatch 的市場(chǎng)名稱,而 libdispatch 作為 Apple 的一個(gè)庫(kù)...
    獨(dú)木舟的木閱讀 1,412評(píng)論 0 5
  • 目錄 一、基本概念1.多線程2.串行和并行, 并發(fā)3.隊(duì)列與任務(wù)4.同步與異步5.線程狀態(tài)6.多線程方案 二、GC...
    BohrIsLay閱讀 1,700評(píng)論 5 12
  • NSThread 第一種:通過(guò)NSThread的對(duì)象方法 NSThread *thread = [[NSThrea...
    攻城獅GG閱讀 955評(píng)論 0 3
  • 刺骨的寒風(fēng)呼呼的吹著,漫長(zhǎng)的夏天終于過(guò)去了。 秋天是冷的,但是路確是香氣逼人。學(xué)校里的桂花樹(shù)一排排立在寬闊的馬路上...
    小崔崔崔崔閱讀 457評(píng)論 0 1

友情鏈接更多精彩內(nèi)容