祭出demo
1、類方法及屬性
/*
類屬性,調(diào)用這個方法時,返回的是當(dāng)前執(zhí)行的線程
*/
@property (class, readonly, strong) NSThread *currentThread;
/*
該類方法會啟動一個線程,并且啟動線程,無需調(diào)用start。
*/
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
/*
該類方法會啟動一個線程,并且啟動線程,無需調(diào)用start。
*/
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
/*設(shè)置當(dāng)前線程sleep到指定時間啟動*/
+ (void)sleepUntilDate:(NSDate *)date;
/*設(shè)置當(dāng)前線程sleep到指定ti秒后啟動*/
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
/*設(shè)置當(dāng)前線程退出,退出的地方不會執(zhí)行exit后面的代碼*/
+ (void)exit;
/*獲取當(dāng)前線程的優(yōu)先級*/
+ (double)threadPriority;
/*設(shè)置當(dāng)前線程的優(yōu)先級,并且返回成功與失敗狀態(tài)*/
+ (BOOL)setThreadPriority:(double)p;
2、實例方法與屬性
/*設(shè)置線程優(yōu)先級,已經(jīng)被棄用,iOS8.0后建議使用qualityOfService*/
@property double threadPriority API_AVAILABLE(macos(10.6), ios(4.0), watchos(2.0), tvos(9.0)); // To be deprecated; use qualityOfService below
/*設(shè)置線程優(yōu)先級,iOS8.0后新增的屬性*/
@property NSQualityOfService qualityOfService API_AVAILABLE(macos(10.10), ios(8.0), watchos(2.0), tvos(9.0)); // read-only after the thread is started
/*
使用target對象的selector作為線程的任務(wù)執(zhí)行體,該selector方法最多可以接收一個參數(shù),該參數(shù)即為argument
*/
- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
/*
使用block作為線程的任務(wù)執(zhí)行體
*/
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
//判斷線程是否正在執(zhí)行
@property (readonly, getter=isExecuting) BOOL executing;
//判斷線程是否結(jié)束
@property (readonly, getter=isFinished) BOOL finished;
//判斷線程是否被取消
@property (readonly, getter=isCancelled) BOOL cancelled;
/*取消線程,調(diào)用后,cancelled會置為YES,但是線程不會真取消,調(diào)用exit之后才會終止*/
- (void)cancel API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
/*啟動線程*/
- (void)start API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
3、簡單事例
//實例
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(threadMehod:) object:@"hi baby"];
[thread setName:@"level low"];
thread.qualityOfService = NSQualityOfServiceBackground;
[thread start];
//類
[NSThread detachNewThreadSelector:@selector(threadMehod:) toTarget:self withObject:@"level"];
- (void)threadMehod:(NSString *)argument {
NSLog(@"threadDictionary=%@",[[NSThread currentThread] threadDictionary]);
for (NSInteger i = 0; i < 20; i++) {
NSLog(@"thread:%@==%@ level=%lX",[NSThread currentThread],argument,(long)[NSThread currentThread].qualityOfService);
[NSThread sleepForTimeInterval:0.1];
}
NSLog(@"thread task complete");
}
4、NSThread的鎖機制
多線程會涉及到競爭條件,可以通過同步機制與鎖機制來解決.
來看看銀行取錢的例子
無處理狀態(tài):
- (void)drawMoney:(NSNumber *)drawCash {
if (self.balance > drawCash.integerValue) {
[NSThread sleepForTimeInterval:0.01];
self.balance -= drawCash.integerValue;
NSLog(@"leave money is %ld in threadName:%@",self.balance,[NSThread currentThread].name);
}else{
NSLog(@"There is not enough money in threadName:%@",[NSThread currentThread].name);
}
}
加鎖處理:
- (void)drawMoneyWithLock:(NSNumber *)drawCash {
[self.lock lock];
if (self.balance > drawCash.integerValue) {
[NSThread sleepForTimeInterval:0.01];
self.balance -= drawCash.integerValue;
NSLog(@"leave money is %ld in threadName:%@",self.balance,[NSThread currentThread].name);
}else{
NSLog(@"There is not enough money in threadName:%@",[NSThread currentThread].name);
}
[self.lock unlock];
}
多個線程碰到lock在使用中時就會等待lock釋放,等lock釋放時,系統(tǒng)就會調(diào)度一個阻塞的線程來取錢了
同步代碼塊
- (void)drawMoneyWithSynchronize:(NSNumber *)drawCash {
@synchronized(self){
if (self.balance > drawCash.integerValue) {
[NSThread sleepForTimeInterval:0.01];
self.balance -= drawCash.integerValue;
NSLog(@"leave money is %ld in threadName:%@",self.balance,[NSThread currentThread].name);
}else{
NSLog(@"There is not enough money in threadName:%@",[NSThread currentThread].name);
}
}
}
@synchronized實現(xiàn)了大括號里的同步代碼塊,同時監(jiān)聽BlankAccount,其他線程需要獲取到監(jiān)聽的BlankAccount才能被調(diào)度。
5、NSCondition有條件的多線程調(diào)度
NS_CLASS_AVAILABLE(10_5, 2_0)
@interface NSCondition : NSObject <NSLocking> {
@private
void *_priv;
}
/*
調(diào)用NSCondition對象wait方法的線程會阻塞,直到其他線程調(diào)用該對象的signal方法或broadcast方法來喚醒
喚醒后該線程從阻塞態(tài)改為就緒態(tài),交由系統(tǒng)進行線程調(diào)度
執(zhí)行wait方法時內(nèi)部會自動執(zhí)行unlock方法釋放鎖,并阻塞線程
*/
- (void)wait;
//同上,只是該方法是在limit到達時喚醒線程
- (BOOL)waitUntilDate:(NSDate *)limit;
/*
喚醒在當(dāng)前NSCondition對象上阻塞的一個線程
如果在該對象上wait的有多個線程則隨機挑選一個,被挑選的線程則從阻塞態(tài)進入就緒態(tài)
*/
- (void)signal;
/*
同上,該方法會喚醒在當(dāng)前NSCondition對象上阻塞的所有線程
*/
- (void)broadcast;
@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));
@end
NSCondition使用示例:
@interface BankAccount : NSObject
@property(nonatomic, strong)NSString *name;
@property(nonatomic, assign)NSInteger balance;
/**
condition的取錢
@param drawCash <#drawCash description#>
*/
- (void)drawMoneyWithCondition:(NSNumber *)drawCash;
/**
condition的存錢
@param depositeCash <#depositeCash description#>
*/
- (void)depositeMoneyWithCondition:(NSNumber *)depositeCash;
@end
@interface BankAccount()
@property (nonatomic, strong)NSCondition *condition;
@property (nonatomic, assign) BOOL haveMoney;
@end
@implementation BankAccount
- (NSCondition *)condition {
@synchronized(self){
/*
這里一定要做同步操作,否則有概率導(dǎo)致被阻塞的線程無法被調(diào)起,可能是系統(tǒng)bug
*/
if (_condition == nil) {
_condition = [[NSCondition alloc]init];
}
}
return _condition;
}
- (void)drawMoneyWithCondition:(NSNumber *)drawCash {
//每個線程取錢20次
NSInteger count = 0;
while (count < 20) {
//首先使用condition上鎖,如果其他線程已經(jīng)上鎖則阻塞
[self.condition lock];
if (self.haveMoney) {
self.balance -= drawCash.integerValue;
self.haveMoney = NO;
count++;
NSLog(@"balance is %ld in threadName:%@ %ld",self.balance,[NSThread currentThread].name,count);
//取錢操作完成后喚醒其他在此condition上等待的線程
[self.condition broadcast];
}else {
//如果沒有錢則在此condition上等待,并阻塞
NSLog(@"draw-> threadName:%@ 阻塞",[NSThread currentThread].name);
[self.condition wait];
NSLog(@"draw-> threadName:%@ 啟動",[NSThread currentThread].name);
}
[self.condition unlock];
}
}
- (void)depositeMoneyWithCondition:(NSNumber *)depositeCash {
//通過2個線程,每次取錢20次,存錢40次
NSInteger count = 0;
while (count < 40) {
[self.condition lock];
if (self.haveMoney == NO) {
self.balance += depositeCash.integerValue;
self.haveMoney = YES;
count++;
NSLog(@"balance is %ld in threadName:%@ %ld",self.balance,[NSThread currentThread].name,count);
//取錢操作完成后喚醒其他在此condition上等待的線程
[self.condition broadcast];
}else {
NSLog(@"deposite-> threadName:%@ 阻塞",[NSThread currentThread].name);
[self.condition wait];
NSLog(@"deposite-> threadName:%@ 啟動",[NSThread currentThread].name);
}
[self.condition unlock];
}
}
@end
線程調(diào)度:
- (void)viewDidLoad {
[super viewDidLoad];
BankAccount *accountTwo = [[BankAccount alloc]init];
accountTwo.name = @"王子銀行";
accountTwo.balance = 0;
NSThread *thread5 = [[NSThread alloc]initWithTarget:accountTwo selector:@selector(drawMoneyWithCondition:) object:@(500)];
[thread5 setName:@"取錢者:豬八戒"];
NSThread *thread6 = [[NSThread alloc]initWithTarget:accountTwo selector:@selector(drawMoneyWithCondition:) object:@(500)];
[thread6 setName:@"取錢者:沙僧"];
NSThread *thread7 = [[NSThread alloc]initWithTarget:accountTwo selector:@selector(depositeMoneyWithCondition:) object:@(500)];
[thread7 setName:@"存錢者:孫悟空"];
[thread5 start];
[thread6 start];
[thread7 start];
}
從控制臺的log可以看出,孫悟空存錢了40次,豬八戒和沙僧分別取錢20次。
如有不清楚的地方請下載demo,有問題請在問候留言