1. 基礎概念
1.1程序:一個 運作
的應用程式,就是一個程序(比如:你iphone上的QQ,微信,MAC電腦上的迅雷,Xcode等)
運作
- 每一個程序之間是互相獨立的,在記憶體中開辟空間
- 一個打開應用程式不一定是一個程序(比如:QQ程式,你開啟多個QQ賬号登入,就
)對應的多個程序
線程:一個程序要執行任務的片段,一條程序至少要有一個線程
- 一個應用程式的所有任務都要在
中執行線程
多線程:是一個程序開啟了多條線程,每條線程同時執行不同的任務
多線程:是一個程序開啟了多條線程,每條線程同時執行不同的任務
主線程
- iOS程式運作之後,預設開啟一條線程,成為主線程或者UI線程
- 主線程是用來:重新整理UI界面,處理UI事件
使用分類
技術 | 簡介 | 語言 | 周期 |
---|---|---|---|
NSThread | [1]面向對象 [2]可直接操作線程 | OC | 程式員自己管理 -> 偶爾使用 |
GCD | [1]代替NSThread 【2】充分利用CPU多核 | C | 程式員自己管理 -> 使用次數頻繁 |
NSOperation | [1]基于GCD 【2】面向對象操作 | OC | 程式員自己管理 -> 使用次數頻繁 |
2.NSThread 線程
2.1基礎認知
- 擷取主線程
NSThread *main = [NSThread mainThread];
NSLog(@"%@",main);
- 擷取目前線程
//擷取目前線程
NSThread *current = [NSThread currentThread];
NSLog(@"-----%@",current);
- 設定線程的名稱屬性
屬性name
- 設定線程的優先級
屬性,threadPriority
範圍0.0-1.0 (預設是0.5)
2.2建立子線程 方法一
//開啟一個線程
- (void)setupTh {
/*
*參數一:目标對象
* 參數二:要執行的g方法
* 參數三:要執行的方法需要傳入的參數值
*/
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction:) object:@"test"];
//設定線程的名稱
thread.name = @"CC";
//啟動線程
[thread start];
}
//要執行的方法
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
}
//列印結果
---<NSThread: 0x600003495fc0>{number = 3, name = CC}----test
2.3 建立子線程 方法二
- (void)setupTwo {
//參數和 方法一的參數 類似
[NSThread detachNewThreadSelector:@selector(handleThreadAction:) toTarget:self withObject:@"text"];
}
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
}
//列印
---<NSThread: 0x6000004da8c0>{number = 3, name = (null)}----text
06-03 16:26:23.173228+0800 01-線程[20338:241267] 不是
3. 隐式線程
- (void)setupThress {
//開啟一個背景子線程
//這個方法的參數 和 上面建立子線程的類似
[self performSelectorInBackground:@selector(handleThreadAction:) withObject:@"建立放大--"];
}
- (void)handleThreadAction:(NSString *)par {
NSLog(@"---%@----%@",[NSThread currentThread],par);
NSLog(@"%@",[NSThread isMainThread] == YES ? @"是" :@"不是");
}
NSThread線程的生命周期是,當任務執行完成才後被釋放這個對象
4.線程的安全問題
出現這個問題的原因,一般為多人同時通路的 共有資源
的時候,會導緻資源的覆寫或者資源資料出錯(比如:售票)
4.1互斥(同步)鎖
@synchronized ("全局屬性") {
//要枷鎖的代碼
}
- 互斥鎖的條件
- 必須是全局
唯一的對象
- 多線程
共享同一塊資源
- 必須是全局
- 互斥鎖的結果
- 線程同步執行
- 耗費性能
- (void)saleoftickets{
self.read1 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read2 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read3 = [[NSThread alloc] initWithTarget:self selector:@selector(handleThreadAction) object:nil];
self.read1.name = @"售票TT";
self.read2.name = @"售票CC";
self.read3.name = @"售票BB";
//啟動線程
[self.read1 start];
//啟動線程
[self.read2 start];
//啟動線程
[self.read3 start];
}
//執行方法
- (void)handleThreadAction{
// synchronized 是消耗性能的,線程使用的鎖對象 必須是同一個對象
// 可以定義一個屬性對象
while (1) {
@synchronized (self) {
for (int i = 0; i < 1000; i ++) {
}
NSUInteger accunt = self.acount;
if (accunt > 0) {
self.acount = accunt - 1;
NSLog(@"%@----%ld",[NSThread currentThread].name,self.acount);
}else {
NSLog(@"售完了。。。。");
break;
}
}
}
}
4.2原子屬性和非原子屬性
-
非原子屬性,沒有加互斥鎖nonatomic
-
原子屬性,為了線程安全,在atomic
加互斥鎖setter
5.線程之間的通信
- 線程之間通信常用的方法
//在子線程中調用 這個方法 就是回到主線程 進行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait
// 從一個線程跳轉到另外一個線程執行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
主要用于:圖檔下載下傳異步操作
6.線程阻塞
- (void)sleepThread {
//阻塞2秒
[NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]];
//阻塞到遙遠的未來
[NSThread sleepUntilDate:[NSDate distantFuture]];
}