iOS多線程編程

一澄峰、進(jìn)程

1.什么是進(jìn)程嫉沽?
  • 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序
  • 每個(gè)進(jìn)程之間是獨(dú)立的,每個(gè)進(jìn)程均運(yùn)行在其專用且受保護(hù)的內(nèi)存空間內(nèi)

二俏竞、線程

1.什么是線程绸硕?
  • 應(yīng)用程序中一條任務(wù)的執(zhí)行路徑
2.進(jìn)程和線程是什么關(guān)系堂竟?
  • 一個(gè)進(jìn)程可以包含多個(gè)線程(一個(gè)進(jìn)程至少包含一個(gè)線程Main線程)
  • 一個(gè)進(jìn)程中的所有任務(wù)都是在線程中執(zhí)行
3.線程中的任務(wù)怎么執(zhí)行?
  • 如果要在一個(gè)線程中執(zhí)行多個(gè)任務(wù)玻佩,那么只能一個(gè)一個(gè)地按順序執(zhí)行這些任務(wù)出嘹,在同一時(shí)間內(nèi),一個(gè)線程只能執(zhí)行一個(gè)任務(wù)
  • 比如在一個(gè)線程中下載三個(gè)文件A咬崔、B税稼、C,那么會(huì)先下載文件A垮斯,然后下載文件B郎仆,再下載文件C
4.什么是多線程
  • 一個(gè)進(jìn)程中可以開啟多條線程,每條線程可以并行(同時(shí))執(zhí)行不同的任務(wù)
  • 比如在一個(gè)線程中下載三個(gè)文件A兜蠕、B扰肌、C,開啟三條線程熊杨,每個(gè)線程下載一個(gè)文件曙旭,那么三個(gè)文件會(huì)同時(shí)去下載
5.多線程實(shí)現(xiàn)原理
  • .同一時(shí)間,CPU只能處理1條線程晶府,只有1條線程在工作(執(zhí)行)
  • .多線程并發(fā)(同時(shí))執(zhí)行桂躏,其實(shí)是CPU快速地在多條線程之間調(diào)度(切換)
  • 如果CPU調(diào)度線程的時(shí)間足夠快,就造成了多線程并發(fā)執(zhí)行
6.多線程的優(yōu)缺點(diǎn)
  • 優(yōu)點(diǎn)一:多線程技術(shù)可以提高程序的執(zhí)行效率
  • 優(yōu)點(diǎn)二:能適當(dāng)提高資源利用率(CPU川陆、內(nèi)存利用率)
  • 缺點(diǎn)一:大量使用多線程CPU會(huì)在N多線程之間調(diào)度沼头,消耗大量的CPU資源,每條線程被調(diào)度執(zhí)行的頻次會(huì)降低(線程的執(zhí)行效率降低)
  • 缺點(diǎn)二:創(chuàng)建線程是有開銷的书劝,iOS下主要成本包括:內(nèi)核數(shù)據(jù)結(jié)構(gòu)(大約1KB)、椡林粒空間(子線程512KB购对、主線程1MB,也可以使用-setStackSize:設(shè)置陶因,但必須是4K的倍數(shù)骡苞,而且最小是16K),創(chuàng)建線程大約需要90毫秒的創(chuàng)建時(shí)間

三楷扬、iOS中多線程實(shí)現(xiàn)方案

iOS中多線程實(shí)現(xiàn)方案

四解幽、pthread

1.C語言API,使用比較麻煩
//開啟新的線程執(zhí)行run方法
- (void)pthread {
    pthread_t thread;
    pthread_create(&thread, NULL, run, NULL);
}

void * run(void *param){
    for (NSInteger i = 0; i<50000; i++) {
        NSLog(@"---------%zd", i);
    }
    return NULL;
}

五、NSThread

1.一個(gè)NSThread對(duì)象就代表一個(gè)線程,以下是幾種創(chuàng)建方式
  • 第一種多線程方式烘苹,需要調(diào)用start方法才能啟動(dòng)
- (void)createThread1{
    // 創(chuàng)建線程,線程對(duì)象(局部變量)系統(tǒng)會(huì)自己加持躲株,在任務(wù)執(zhí)行完之前不會(huì)被銷毀
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];
    thread.name = @"my-thread";
    // 啟動(dòng)線程
    [thread start];
}

- (void)run:(NSString *)param{
    for (NSInteger i = 0; i<100; i++) {
        NSLog(@"------%@", [NSThread currentThread]);
    }
}

  • 第二種多線程方式,創(chuàng)建線程后自動(dòng)啟動(dòng)線程
- (void)createThread2{
    [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"rose"];
}
- (void)run:(NSString *)param{
    for (NSInteger i = 0; i<100; i++) {
        NSLog(@"------%@", [NSThread currentThread]);
    }
}
  • 第三種多線程方式镣衡,隱式創(chuàng)建并啟動(dòng)線程
- (void)createThread3{
    [self performSelectorInBackground:@selector(run:) withObject:@"jack"];
}
- (void)run:(NSString *)param{
    for (NSInteger i = 0; i<100; i++) {
        NSLog(@"------%@", [NSThread currentThread]);
    }
}
2.NSThread的線程通信
  • 在一個(gè)線程中執(zhí)行完特定任務(wù)后霜定,轉(zhuǎn)到另一個(gè)線程繼續(xù)執(zhí)行任務(wù)档悠,一個(gè)線程傳遞數(shù)據(jù)給另一個(gè)線程,API如下:
- (void)performSelectorOnMainThread:(SEL)aSelector 
                         withObject:(id)arg 
                      waitUntilDone:(BOOL)wait;

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

  • 線程通信示例:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    [self performSelectorInBackground:@selector(download3) withObject:nil];
}

//子線程下載圖片數(shù)據(jù)
- (void)download3{
    NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
    NSData *data = [NSData dataWithContentsOfURL:url];
    UIImage *image = [UIImage imageWithData:data];
    
    // 回到主線程,顯示圖片
    [self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
    //[self.imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:NO];
    //[self performSelectorOnMainThread:@selector(showImage:) withObject:image waitUntilDone:YES];

    NSLog(@" --- waitUntilDone ---");
    //waitUntilDone參數(shù):
    //YES:會(huì)等到setImage方法走完以后打印最后一句log望浩。
    //NO:在執(zhí)行setImage方法的時(shí)候不影響最后一句log的打印辖所,兩個(gè)是同時(shí)進(jìn)行
}

//主線程顯示圖片
- (void)showImage:(UIImage *)image{
    self.imageView.image = image;
}

3.NSThread常用的方法
//獲得當(dāng)前線程
NSThread *current = [NSThread currentThread];

+ (NSThread *)mainThread; // 獲得主線程
- (BOOL)isMainThread; // 是否為主線程
+ (BOOL)isMainThread; // 是否為主線程

//線程的名字,適用于第一種方式創(chuàng)建的線程(創(chuàng)建的時(shí)候返回NSThread的對(duì)象)
- (void)setName:(NSString *)n;
- (NSString *)name;

六、GCD

1.什么是GCD
  • 全稱是Grand Central Dispatch磨德,可譯為“重要的中樞調(diào)度器”
  • GCD是蘋果公司為多核的并行運(yùn)算提出的解決方案
  • GCD會(huì)自動(dòng)利用更多的CPU內(nèi)核(比如雙核缘回、四核)
  • GCD會(huì)自動(dòng)管理線程的生命周期(創(chuàng)建線程、調(diào)度任務(wù)典挑、銷毀線程)
2.任務(wù):執(zhí)行什么操作
  • 用同步的方式執(zhí)行任務(wù):
dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
  • 用異步的方式執(zhí)行任務(wù)
dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
  • 同步和異步的區(qū)別

同步:只能在當(dāng)前線程中執(zhí)行任務(wù)酥宴,不具備開啟新線程的能力
異步:可以在新的線程中執(zhí)行任務(wù),具備開啟新線程的能力

3.隊(duì)列
  • 并發(fā)隊(duì)列(Concurrent Dispatch Queue)

可以讓多個(gè)任務(wù)并發(fā)(同時(shí))執(zhí)行(自動(dòng)開啟多個(gè)線程同時(shí)執(zhí)行任務(wù))
并發(fā)功能只有在異步(dispatch_async)函數(shù)下才有效

  • 串行隊(duì)列(Serial Dispatch Queue)

讓任務(wù)一個(gè)接著一個(gè)地執(zhí)行(一個(gè)任務(wù)執(zhí)行完畢后搔弄,再執(zhí)行下一個(gè)任務(wù))

  • 獲取并發(fā)隊(duì)列
GCD默認(rèn)已經(jīng)提供了全局的并發(fā)隊(duì)列幅虑,供整個(gè)應(yīng)用使用,不需要手動(dòng)創(chuàng)建
使用dispatch_get_global_queue函數(shù)獲得全局的并發(fā)隊(duì)列
dispatch_queue_t dispatch_get_global_queue(
dispatch_queue_priority_t priority, // 隊(duì)列的優(yōu)先級(jí)
unsigned long flags); // 此參數(shù)暫時(shí)無用顾犹,用0即可
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); // 獲得全局并發(fā)隊(duì)列

全局并發(fā)隊(duì)列的優(yōu)先級(jí)
#define DISPATCH_QUEUE_PRIORITY_HIGH 2 // 高
#define DISPATCH_QUEUE_PRIORITY_DEFAULT 0 // 默認(rèn)(中)
#define DISPATCH_QUEUE_PRIORITY_LOW (-2) // 低
#define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MI

//自己創(chuàng)建一個(gè)并發(fā)隊(duì)列
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_CONCURRENT);
  • 獲取串行隊(duì)列
GCD中獲得串行有2種途徑
使用dispatch_queue_create函數(shù)創(chuàng)建串行隊(duì)列
dispatch_queue_t
dispatch_queue_create(const char *label, // 隊(duì)列名稱 
dispatch_queue_attr_t attr); // 隊(duì)列屬性倒庵,一般用NULL即可,DISPATCH_QUEUE_SERIAL串行就傳NULL
dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL); // 創(chuàng)建
dispatch_release(queue); // 非ARC需要釋放手動(dòng)創(chuàng)建的隊(duì)列

使用主隊(duì)列(跟主線程相關(guān)聯(lián)的隊(duì)列)
主隊(duì)列是GCD自帶的一種特殊的串行隊(duì)列
放在主隊(duì)列中的任務(wù),都會(huì)放到主線程中執(zhí)行
使用dispatch_get_main_queue()獲得主隊(duì)列
dispatch_queue_t queue = dispatch_get_main_queue();
  • 各種隊(duì)列和發(fā)送方法的組合
// 同步函數(shù) + 主隊(duì)列:(若是在主線程調(diào)用會(huì)卡死主線程)
- (void)syncMain{
    NSLog(@"syncMain ----- begin");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    NSLog(@"syncMain ----- end");
}

// 異步函數(shù) + 主隊(duì)列:只在主線程中執(zhí)行任務(wù)
- (void)asyncMain{
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
}


 //同步函數(shù) + 串行隊(duì)列:不會(huì)開啟新的線程炫刷,在當(dāng)前線程執(zhí)行任務(wù)擎宝。任務(wù)是串行的,執(zhí)行完一個(gè)任務(wù)浑玛,再執(zhí)行下一個(gè)任務(wù)
- (void)syncSerial{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
}

 //異步函數(shù) + 串行隊(duì)列:會(huì)開啟新的線程绍申,但是任務(wù)是串行的,執(zhí)行完一個(gè)任務(wù)顾彰,再執(zhí)行下一個(gè)任務(wù)
- (void)asyncSerial{
    dispatch_queue_t queue = dispatch_queue_create("queue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
}


 //同步函數(shù) + 并發(fā)隊(duì)列:不會(huì)開啟新的線程
- (void)syncConcurrent{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_sync(queue, ^{
        NSLog(@"1-----%@", [NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        NSLog(@"2-----%@", [NSThread currentThread]);
    });
    //會(huì)先執(zhí)行任務(wù)再執(zhí)行這句打印极阅,sync的任務(wù)會(huì)立刻執(zhí)行
    NSLog(@"syncConcurrent--------end");
}


// 異步函數(shù) + 并發(fā)隊(duì)列:可以同時(shí)開啟多條線程
- (void)asyncConcurrent{
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"1-----%@", [NSThread currentThread]);
        }
    });
    dispatch_async(queue, ^{
        for (NSInteger i = 0; i<10; i++) {
            NSLog(@"2-----%@", [NSThread currentThread]);
        }
    });
    //會(huì)先執(zhí)行這一句打印,再執(zhí)行添加到隊(duì)列里面的任務(wù)
    NSLog(@"asyncConcurrent--------end");
}
  • 各種組合圖示


    各種組合圖示
  • GCD中的實(shí)用方法
//1.延遲執(zhí)行
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
});

//2.一次性代碼:使用dispatch_once函數(shù)能保證某段代碼在程序運(yùn)行過程中只被執(zhí)行1次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    // 只執(zhí)行1次的代碼(這里面默認(rèn)是線程安全的)
});

//3.隊(duì)列組
//分別異步執(zhí)行2個(gè)耗時(shí)的操作,等2個(gè)異步操作都執(zhí)行完畢后涨享,再回到主線程執(zhí)行操作
dispatch_group_t group =  dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    // 執(zhí)行1個(gè)耗時(shí)的異步操作
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
    // 等前面的異步操作都執(zhí)行完畢后筋搏,回到主線程...
});

//4.快速迭代
dispatch_apply(10, queue, ^(size_t index) {
     //queue如果是串行隊(duì)列index是有順序的
     //queue如果是并發(fā)隊(duì)列index是無序的(并發(fā)執(zhí)行)
});

//5.barrier函數(shù):保證barrier之前的任務(wù)是并發(fā)執(zhí)行,然后執(zhí)行barrier任務(wù)厕隧,然后執(zhí)行barrier之后的任務(wù)
- (void)barrier{
    dispatch_queue_t queue = dispatch_queue_create("12312312", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"----1-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----2-----%@", [NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"----barrier-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----3-----%@", [NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"----4-----%@", [NSThread currentThread]);
    });
}

七奔脐、NSOperation

1.NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
  • NSOperation和NSOperationQueue是對(duì)GCD的一層封裝
  • NSOperation和NSOperationQueue實(shí)現(xiàn)多線程的具體步驟
  • 先將需要執(zhí)行的操作封裝到一個(gè)NSOperation對(duì)象中
  • 然后將NSOperation對(duì)象添加到NSOperationQueue中
  • 系統(tǒng)會(huì)自動(dòng)將NSOperationQueue中的NSOperation取出來
  • 將取出的NSOperation封裝的操作放到一條新線程中執(zhí)行
2.NSOperation:是個(gè)抽象類,并不具備封裝操作的能力吁讨,必須使用它的子類
  • NSInvocationOperation
//默認(rèn)情況下滔悉,調(diào)用了start方法后并不會(huì)開一條新線程去執(zhí)行操作祝沸,而是在當(dāng)前線程同步執(zhí)行操作
//只有將NSOperation放到一個(gè)NSOperationQueue中,才會(huì)異步執(zhí)行操作
- (void)invocationOperation{
    NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nil];
    [op start];
}

- (void)run{
    NSLog(@"------%@", [NSThread currentThread]);
}
  • NSBlockOperation
//只要NSBlockOperation封裝的操作數(shù) > 1,就會(huì)異步執(zhí)行操作
- (void)blockOperation{
    NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
        // 在主線程
        NSLog(@"下載1------%@", [NSThread currentThread]);
    }];
    
    // 添加額外的任務(wù)(在子線程執(zhí)行)
    [op addExecutionBlock:^{
        NSLog(@"下載2------%@", [NSThread currentThread]);
    }];
    
    [op start];
}
3.NSOperationQueue
  • NSOperation可以調(diào)用start方法來執(zhí)行任務(wù)版扩,但默認(rèn)是同步執(zhí)行的
  • 如果將NSOperation添加到NSOperationQueue(操作隊(duì)列)中布讹,系統(tǒng)會(huì)自動(dòng)異步執(zhí)行NSOperation中的操作
  • 添加操作到NSOperationQueue中
- (void)addOperation:(NSOperation *)op;//添加op的時(shí)候會(huì)默認(rèn)調(diào)用[op start];
- (void)addOperationWithBlock:(void (^)(void))block;//會(huì)默認(rèn)調(diào)用[op start];
4.NSOperation和NSOperationQueue的組合使用
  • NSInvocationOperation和NSOperationQueue
- (void)operationQueue1{
    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    // 創(chuàng)建NSInvocationOperation
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
    
    // 添加任務(wù)到隊(duì)列中
    [queue addOperation:op1]; // [op1 start]
    [queue addOperation:op2]; // [op2 start]
}

- (void)download1{
    NSLog(@"download1 --- %@", [NSThread currentThread]);
}

- (void)download2{
    NSLog(@"download2 --- %@", [NSThread currentThread]);
}
  • NSBlockOperation和NSOperationQueue的組合使用
- (void)operationQueue1{
    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 創(chuàng)建NSBlockOperation
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download3 --- %@", [NSThread currentThread]);
    }];
    
    [op3 addExecutionBlock:^{
        NSLog(@"download4 --- %@", [NSThread currentThread]);
    }];
    [op3 addExecutionBlock:^{
        NSLog(@"download5 --- %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"download6 --- %@", [NSThread currentThread]);
    }];
    
    // 添加任務(wù)到隊(duì)列中
    [queue addOperation:op3]; // [op3 start]
    [queue addOperation:op4]; // [op4 start]
}
5.如果控制NSOperationQueue是串行隊(duì)列還是并發(fā)隊(duì)列
  • 默認(rèn)最大并發(fā)數(shù)是-1,也就是不限制最大并發(fā)數(shù),當(dāng)有多個(gè)任務(wù)的時(shí)候會(huì)開啟多條線程同時(shí)執(zhí)行任務(wù)
  • maxConcurrentOperationCount:同時(shí)執(zhí)行的任務(wù)個(gè)數(shù)
- (void)maxConcurrentOperationCountTest {
    
    // 創(chuàng)建隊(duì)列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
   // 變成了串行隊(duì)列,會(huì)開啟一條線程艰亮,任務(wù)依次執(zhí)行
    queue.maxConcurrentOperationCount = 1; 
    
    // 添加操作
    [queue addOperationWithBlock:^{
        NSLog(@"download1 --- %@", [NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"download2 --- %@", [NSThread currentThread]);
    }];
}
6.隊(duì)列的取消、暫停挣郭、恢復(fù)
  • 取消隊(duì)列的所有操作
- (void)cancelAllOperations;
//也可以調(diào)用NSOperation的- (void)cancel方法取消單個(gè)操作
  • 暫停和恢復(fù)隊(duì)列
- (void)setSuspended:(BOOL)b; // YES代表暫停隊(duì)列迄埃,NO代表恢復(fù)隊(duì)列
- (BOOL)isSuspended;
7.操作的相互依賴:NSOperation之間可以設(shè)置依賴來保證執(zhí)行順序
  • 比如一定要讓操作A執(zhí)行完后,才能執(zhí)行操作B兑障,可以這么寫
[operationB addDependency:operationA]; // 操作B依賴于操作A
  • 任務(wù)可以夸隊(duì)列依賴侄非,在不同隊(duì)列里面的任務(wù)也可以相互依賴


    任務(wù)的跨隊(duì)列依賴
  • 任務(wù)不可以相互依賴,會(huì)卡死:

[operationB addDependency:operationA]; // 操作B依賴于操作A
[operationA addDependency:operationB]; // 操作A依賴于操作B

八流译、線程狀態(tài)

1.線程狀態(tài)
  • 創(chuàng)建一個(gè)線程調(diào)用了start方法以后線程對(duì)象會(huì)放入可調(diào)度線程池逞怨,進(jìn)入就緒狀態(tài),等待CPU的調(diào)度
  • 當(dāng)CPU調(diào)度的時(shí)候處于runing狀態(tài)福澡,當(dāng)CPU調(diào)用其他線程的時(shí)候當(dāng)前線程會(huì)進(jìn)入就緒狀態(tài)
  • 調(diào)用了sleep方法\等待同步鎖會(huì)進(jìn)入阻塞狀態(tài)
  • sleep到時(shí)\得到同步鎖進(jìn)入就緒狀態(tài)
  • 線程任務(wù)執(zhí)行完畢叠赦、異常\強(qiáng)制退出,進(jìn)入死亡狀態(tài)
2.線程狀態(tài)示意圖:
線程狀態(tài)示意圖
3.線程狀態(tài)相關(guān)方法
啟動(dòng)線程
- (void)start; 
// 進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)革砸。當(dāng)線程任務(wù)執(zhí)行完畢除秀,自動(dòng)進(jìn)入死亡狀態(tài)

阻塞(暫停)線程
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 進(jìn)入阻塞狀態(tài)

強(qiáng)制停止線程
+ (void)exit;
// 進(jìn)入死亡狀態(tài)

注意:一旦線程停止(死亡)了,就不能再次開啟任務(wù)

九算利、多線程資源搶奪

1.資源搶奪簡(jiǎn)述:
  • 一塊資源可能會(huì)被多個(gè)線程共享册踩,也就是多個(gè)線程可能會(huì)訪問同一塊資源,比如多個(gè)線程訪問同一個(gè)對(duì)象效拭、同一個(gè)變量暂吉、同一個(gè)文件
  • 當(dāng)多個(gè)線程訪問同一塊資源時(shí),很容易引發(fā)數(shù)據(jù)錯(cuò)亂和數(shù)據(jù)安全問題
2.資源搶奪示意圖:
資源搶奪示意圖
3.線程同步(互斥鎖)
  • 線程同步:多條線程在同一條線上執(zhí)行(按順序地執(zhí)行任務(wù)),互斥鎖缎患,就是使用了線程同步技術(shù).
  • 互斥鎖對(duì)某段代碼進(jìn)行加鎖
  • 一個(gè)線程在進(jìn)入之前會(huì)判斷鎖的狀態(tài)是否是打開慕的,若果是打開則加鎖,然后進(jìn)入代碼進(jìn)行操作挤渔,操作完成后解鎖业稼。在操作過程中如果有其他線程想對(duì)這段代碼進(jìn)行操作則需要等待鎖放開才能進(jìn)入操作
  • 互斥鎖雖然能有效解決多線程的資源搶奪問題,同時(shí)需要消耗大量的CPU資源
//注意:鎖定1份代碼只用1把鎖蚂蕴,用多把鎖是無效的(一般self即可)
@synchronized(鎖對(duì)象) {
 // 需要鎖定的代碼  
}
4.互斥鎖的原理
互斥鎖的原理
5.原子和非原子屬性
  • OC在定義屬性時(shí)有nonatomic和atomic兩種選擇
  • atomic:原子屬性,為setter方法加鎖,是線程安全的(默認(rèn)就是atomic)
  • nonatomic:非原子屬性俯邓,不會(huì)為setter方法加鎖

十骡楼、多線程下載多圖片示例

多線程下載多圖片demo 密碼:94ts

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市稽鞭,隨后出現(xiàn)的幾起案子鸟整,更是在濱河造成了極大的恐慌,老刑警劉巖朦蕴,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件篮条,死亡現(xiàn)場(chǎng)離奇詭異弟头,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)涉茧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門赴恨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人伴栓,你說我怎么就攤上這事伦连。” “怎么了钳垮?”我有些...
    開封第一講書人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵惑淳,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我饺窿,道長(zhǎng)歧焦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任肚医,我火速辦了婚禮绢馍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘忍宋。我一直安慰自己痕貌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開白布糠排。 她就那樣靜靜地躺著舵稠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪入宦。 梳的紋絲不亂的頭發(fā)上哺徊,一...
    開封第一講書人閱讀 49,772評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音乾闰,去河邊找鬼落追。 笑死,一個(gè)胖子當(dāng)著我的面吹牛涯肩,可吹牛的內(nèi)容都是我干的轿钠。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼病苗,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼疗垛!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起硫朦,我...
    開封第一講書人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤贷腕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體泽裳,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瞒斩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了涮总。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胸囱。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖妹卿,靈堂內(nèi)的尸體忽然破棺而出旺矾,到底是詐尸還是另有隱情,我是刑警寧澤夺克,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布箕宙,位于F島的核電站,受9級(jí)特大地震影響铺纽,放射性物質(zhì)發(fā)生泄漏柬帕。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一狡门、第九天 我趴在偏房一處隱蔽的房頂上張望陷寝。 院中可真熱鬧,春花似錦其馏、人聲如沸凤跑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仔引。三九已至,卻和暖如春褐奥,著一層夾襖步出監(jiān)牢的瞬間咖耘,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來泰國打工撬码, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留儿倒,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓呜笑,卻偏偏與公主長(zhǎng)得像夫否,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子叫胁,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

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

  • 目錄 一慷吊、多線程簡(jiǎn)介 1、多線程的由來2曹抬、耗時(shí)操作的模擬試驗(yàn)3、進(jìn)程和線程4、多線程的概念及原理5谤民、多線程的優(yōu)缺點(diǎn)...
    寧梓茞閱讀 522評(píng)論 0 0
  • iOS多線程編程 基本知識(shí) 1. 進(jìn)程(process) 進(jìn)程是指在系統(tǒng)中正在運(yùn)行的一個(gè)應(yīng)用程序堰酿,就是一段程序的執(zhí)...
    陵無山閱讀 6,021評(píng)論 1 14
  • 一.概述 1.基本概念 同步與異步的概念 同步 必須等待當(dāng)前語句執(zhí)行完畢,才可以執(zhí)行下一個(gè)語句张足。 異步 不用等待當(dāng)...
    Jt_Self閱讀 471評(píng)論 0 1
  • 概覽 進(jìn)程與線程的概念 多線程的由來 并行與并發(fā) 多線程的實(shí)現(xiàn) 串行與并行 線程的幾種狀態(tài) 串行隊(duì)列與并發(fā)隊(duì)列區(qū)別...
    a_只羊閱讀 221評(píng)論 0 0
  • 文/雪諾 微信公眾號(hào):迷茫人生路 總是喜歡在自己迷茫無助的時(shí)候去尋求一絲慰藉为牍,失敗時(shí)的傾訴哼绑、傷心時(shí)的哭...
    Snow鳳閱讀 105評(píng)論 0 0