一. NSThread開啟新的線程
1. 創(chuàng)建并啟動(dòng)線程
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadData) object:nil];
[thread start];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x600000eecc80>{number = 3, name = (null)}
2. 創(chuàng)建并啟動(dòng)線程
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x6000028049c0>{number = 3, name = (null)}
3. 隱式創(chuàng)建線程并啟動(dòng)
[self performSelectorInBackground:@selector(loadData) withObject:nil];
- (void)loadData{
NSLog(@"%@", [NSThread currentThread]);
}
<NSThread: 0x600001848cc0>{number = 3, name = (null)}
二. NSThread多線程常用相關(guān)方法
1. 線程屬性相關(guān)
// 獲得主線程
+ (NSThread *)mainThread;
// 判斷是否為主線程(對(duì)象方法)
- (BOOL)isMainThread;
// 判斷是否為主線程(類方法)
+ (BOOL)isMainThread;
// 獲得當(dāng)前線程
NSThread *thread = [NSThread currentThread];
// 線程的名字——setter方法
- (void)setName:(NSString *)n;
// 線程的名字——getter方法
- (NSString *)name;
2. 線程狀態(tài)控制相關(guān)
// 線程進(jìn)入就緒狀態(tài) -> 運(yùn)行狀態(tài)吁断。當(dāng)線程任務(wù)執(zhí)行完畢躲查,自動(dòng)進(jìn)入死亡狀態(tài)
// 啟動(dòng)線程方法
- (void)start;
// 阻塞(暫停)線程方法
// 線程進(jìn)入阻塞狀態(tài)
+ (void)sleepUntilDate:(NSDate *)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
// 強(qiáng)制停止線程
// 線程進(jìn)入死亡狀態(tài)
+ (void)exit;
3. 線程執(zhí)行操作相關(guān)
// 在主線程上執(zhí)行操作
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray<NSString *> *)array;
// equivalent to the first method with kCFRunLoopCommonModes
// 在指定線程上執(zhí)行操作
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
// 在當(dāng)前線程上執(zhí)行操作奸例,調(diào)用 NSObject 的 performSelector:相關(guān)方法
- (id)performSelector:(SEL)aSelector;
- (id)performSelector:(SEL)aSelector withObject:(id)object;
- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
三. NSThread線程之間的通信
先開一個(gè)新的子線程執(zhí)行耗時(shí)操作轻猖,然后回到主線程中刷新UI甚颂。
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
- (void)loadData{
NSLog(@"1.%@", [NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0];
[self performSelectorOnMainThread:@selector(reloadUI) withObject:nil waitUntilDone:YES];
}
- (void)reloadUI{
NSLog(@"2.%@", [NSThread currentThread]);
}
1.<NSThread: 0x600001a57a80>{number = 3, name = (null)}
2.<NSThread: 0x600001a062c0>{number = 1, name = main}
四. 線程安全
需求:有時(shí)候用爪,我們會(huì)在多個(gè)地方同時(shí)對(duì)同一個(gè)接口進(jìn)行調(diào)用顽照,那如果每次調(diào)用過程會(huì)對(duì)下一次調(diào)用的結(jié)果有影響(有修改或者更變等操作)无畔,那么我們就必須保證該接口同一時(shí)間只能被一個(gè)地方調(diào)用宅粥,這就是線程安全
参袱。
- (void)viewDidLoad {
[super viewDidLoad];
for (int i = 0; i < 10; i ++) {
[NSThread detachNewThreadSelector:@selector(loadData) toTarget:self withObject:nil];
}
}
- (void)loadData{
@synchronized (self) {
// 模擬耗時(shí)操作
[NSThread sleepForTimeInterval:1.0];
NSLog(@"---");
}
}
注:@synchronized
的作用是創(chuàng)建一個(gè)互斥鎖
,這個(gè)指令可以將{ }
內(nèi)的代碼限制在一個(gè)線程執(zhí)行,如果某個(gè)線程沒有執(zhí)行完抹蚀,其他的線程如果需要執(zhí)行就得等著,起到線程的保護(hù)作用剿牺。
五. 線程狀態(tài)總結(jié)
線程狀態(tài)圖.png
- 當(dāng)線程創(chuàng)建之后被啟動(dòng),進(jìn)入
就緒狀態(tài)
环壤。 - 當(dāng)線程被
CPU
調(diào)度晒来,進(jìn)入運(yùn)行狀態(tài)
。 - 當(dāng)
CPU
去調(diào)度其他線程郑现,回到就緒狀態(tài)
湃崩。 - 當(dāng)
CPU
在運(yùn)行當(dāng)前線程對(duì)象的時(shí)候調(diào)用了sleep
方法或者等待同步鎖
,進(jìn)入阻塞狀態(tài)
接箫。等到sleep
到時(shí)或者得到同步鎖
攒读,則回到就緒狀態(tài)
。 - 當(dāng)
CPU
在運(yùn)行當(dāng)前線程對(duì)象的時(shí)候線程任務(wù)執(zhí)行完畢或者異常強(qiáng)制退出辛友,則當(dāng)前線程對(duì)象進(jìn)入死亡狀態(tài)
薄扁。