iOS多線程-NSthread

祭出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,有問題請在問候留言

祭出demo
更新時間: 2018-08-23

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容