在日常開(kāi)發(fā)中,能用到的多線程知識(shí)點(diǎn)有NSThread,NSOperationQueue,GCD。至于Pthreads,因?yàn)榛居貌坏剑秃雎圆挥?jì)了。
多線程基本知識(shí)
進(jìn)程: 一個(gè)具有一定獨(dú)立功能的程序關(guān)于某個(gè)數(shù)據(jù)集合的一次運(yùn)行活動(dòng)。可以理解成一個(gè)運(yùn)行中的應(yīng)用程序。
線程: 程序執(zhí)行流的最小單元,線程是進(jìn)程中的一個(gè)實(shí)體。
同步: 只能在當(dāng)前線程按先后順序依次執(zhí)行,不開(kāi)啟新線程。
異步: 可以在當(dāng)前線程開(kāi)啟多個(gè)新線程執(zhí)行,可不按順序執(zhí)行。
隊(duì)列: 裝載線程任務(wù)的隊(duì)形結(jié)構(gòu)。
并發(fā): 線程執(zhí)行可以同時(shí)一起進(jìn)行執(zhí)行。
串行: 線程執(zhí)行只能依次逐一先后有序的執(zhí)行。
具體組合如下
| 同步執(zhí)行 | 異步執(zhí)行 | |
|---|---|---|
| 串行隊(duì)列 | 當(dāng)前線程,一個(gè)一個(gè)執(zhí)行 | 其他線程,一個(gè)一個(gè)執(zhí)行 |
| 并行隊(duì)列 | 當(dāng)前線程,一個(gè)一個(gè)執(zhí)行 | 開(kāi)很多線程,一起執(zhí)行 |
多線程比較
NSThread
先看一下NSThread的相關(guān)屬性方法
@interface NSThread : NSObject
//當(dāng)前線程
@property (class, readonly, strong) NSThread *currentThread;
//使用類(lèi)方法創(chuàng)建線程執(zhí)行任務(wù)
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
//判斷當(dāng)前是否為多線程
+ (BOOL)isMultiThreaded;
//指定線程的線程參數(shù),例如設(shè)置當(dāng)前線程的斷言處理器。
@property (readonly, retain) NSMutableDictionary *threadDictionary;
//當(dāng)前線程暫停到某個(gè)時(shí)間
+ (void)sleepUntilDate:(NSDate *)date;
//當(dāng)前線程暫停一段時(shí)間
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
//退出當(dāng)前線程
+ (void)exit;
//當(dāng)前線程優(yōu)先級(jí)
+ (double)threadPriority;
//設(shè)置當(dāng)前線程優(yōu)先級(jí)
+ (BOOL)setThreadPriority:(double)p;
//指定線程對(duì)象優(yōu)先級(jí) 0.0~1.0,默認(rèn)值為0.5
@property double threadPriority NS_AVAILABLE(10_6, 4_0);
//服務(wù)質(zhì)量
@property NSQualityOfService qualityOfService NS_AVAILABLE(10_10, 8_0);
//線程名稱(chēng)
@property (nullable, copy) NSString *name NS_AVAILABLE(10_5, 2_0);
//棧區(qū)大小
@property NSUInteger stackSize NS_AVAILABLE(10_5, 2_0);
//是否為主線程
@property (class, readonly) BOOL isMainThread NS_AVAILABLE(10_5, 2_0);
//獲取主線程
@property (class, readonly, strong) NSThread *mainThread NS_AVAILABLE(10_5, 2_0);
//初始化
- (instancetype)init NS_AVAILABLE(10_5, 2_0) NS_DESIGNATED_INITIALIZER;
//實(shí)例方法初始化,需要再調(diào)用start方法
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument NS_AVAILABLE(10_5, 2_0);
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
//線程狀態(tài),正在執(zhí)行
@property (readonly, getter=isExecuting) BOOL executing NS_AVAILABLE(10_5, 2_0);
//線程狀態(tài),正在完成
@property (readonly, getter=isFinished) BOOL finished NS_AVAILABLE(10_5, 2_0);
//線程狀態(tài),已經(jīng)取消
@property (readonly, getter=isCancelled) BOOL cancelled NS_AVAILABLE(10_5, 2_0);
//取消,僅僅改變線程狀態(tài),并不能像exist一樣真正的終止線程
- (void)cancel NS_AVAILABLE(10_5, 2_0);
//開(kāi)始
- (void)start NS_AVAILABLE(10_5, 2_0);
//線程需要執(zhí)行的代碼,一般寫(xiě)子類(lèi)的時(shí)候會(huì)用到
- (void)main NS_AVAILABLE(10_5, 2_0);
@end
另外,還有一個(gè)NSObject的分類(lèi),瞅一眼:
@interface NSObject (NSThreadPerformAdditions)
//隱式的創(chuàng)建并啟動(dòng)線程,并在指定的線程(主線程或子線程)上執(zhí)行方法。
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait modes:(nullable NSArray *)array;
- (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 modes:(nullable NSArray *)array NS_AVAILABLE(10_5, 2_0);
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(nullable id)arg waitUntilDone:(BOOL)wait NS_AVAILABLE(10_5, 2_0);
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg NS_AVAILABLE(10_5, 2_0);
@end
以上有兩個(gè)帶有selector創(chuàng)建線程的方法,selector和target是有對(duì)應(yīng)關(guān)系的,應(yīng)該是target的selector方法,不能一貫的寫(xiě)self
創(chuàng)建線程示例
ViewController.m
#import "ViewController.h"
#import "Person.h"
@interface ViewController ()
@property (nonatomic, strong) Person *person;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.person = [[Person alloc]init];
self.person = [[Person alloc]init];
[NSThread detachNewThreadSelector:@selector(sayHello:) toTarget:self.person withObject:@"Jim"];
// 崩潰,self沒(méi)有sayHello()方法
// [NSThread detachNewThreadSelector:@selector(sayHello:) toTarget:self withObject:@"Jim"];
NSThread *thread = [[NSThread alloc]initWithTarget:self.person selector:@selector(sayHello:) object:@"Sam"];
// 崩潰,self沒(méi)有sayHello()方法
// NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(sayHello:) object:@"Sam"];
[thread start];
}
@end
Person類(lèi)
//Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
- (void)sayHello:(NSString *)name;
@end
//Person.m
#import "Person.h"
@implementation Person
- (void)sayHello:(NSString *)name{
NSLog(@"Hello, %@", name);
NSLog(@"hello %@",[NSThread currentThread]);
}
@end
用NSThread下載圖片阻塞示例:
//為開(kāi)辟線程按鈕事件
- (IBAction)blockTest:(id)sender {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"Hint" message:@"Just For Test" delegate:nil cancelButtonTitle:@"YES" otherButtonTitles: nil];
[alert show];
}
//開(kāi)辟新線程按鈕時(shí)間
- (IBAction)noMultiAction:(id)sender {
[self loadImage];
}
-(void)loadImage{
NSURL *imageUrl = [NSURL URLWithString:kImageUrl];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
[self updateImageData:imageData];
}
-(void)updateImageData:(NSData*)imageData{
UIImage *image = [UIImage imageWithData:imageData];
[self performSelectorOnMainThread:@selector(updateImageOnMainThread:) withObject:image waitUntilDone:NO]; //更新UI的部分應(yīng)該在主線程
}
- (void)updateImageOnMainThread:(UIImage *)image{
self.showImageView.image = image;
}
- (IBAction)multiAction:(id)sender {
[NSThread detachNewThreadSelector:@selector(loadImage) toTarget:self withObject:nil];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
點(diǎn)擊左側(cè)按鈕效果如下:

點(diǎn)擊右側(cè)按鈕效果如下:

用多線程果然能解決線程阻塞的問(wèn)題,并且NSThread也比Pthreads好用,只不過(guò)實(shí)際開(kāi)發(fā)中也許只有[NSThread currentThread];用的最多了。所以?xún)H僅NSThread是不能滿足我們的需要的。那就需要另外的手段了,比如GCD。