iOS多线程-NSthread

祭出demo
1、类方法及属性

/*
类属性,调用这个方法时,返回的是当前执行的线程
*/
@property (class, readonly, strong) NSThread *currentThread;

/*
该类方法会启动一个线程,并且启动线程,无需调用start。
*/
+ (void)detachNewThreadWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

/*
该类方法会启动一个线程,并且启动线程,无需调用start。
*/
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;
/*设置当前线程sleep到指定时间启动*/
+ (void)sleepUntilDate:(NSDate *)date;
/*设置当前线程sleep到指定ti秒后启动*/
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
/*设置当前线程退出,退出的地方不会执行exit后面的代码*/
+ (void)exit;
/*获取当前线程的优先级*/
+ (double)threadPriority;
/*设置当前线程的优先级,并且返回成功与失败状态*/
+ (BOOL)setThreadPriority:(double)p;

2、实例方法与属性

/*设置线程优先级,已经被弃用,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
/*设置线程优先级,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作为线程的任务执行体,该selector方法最多可以接收一个参数,该参数即为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作为线程的任务执行体
*/
- (instancetype)initWithBlock:(void (^)(void))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));

//判断线程是否正在执行
@property (readonly, getter=isExecuting) BOOL executing;

//判断线程是否结束
@property (readonly, getter=isFinished) BOOL finished;

//判断线程是否被取消
@property (readonly, getter=isCancelled) BOOL cancelled;

/*取消线程,调用后,cancelled会置为YES,但是线程不会真取消,调用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的锁机制
多线程会涉及到竞争条件,可以通过同步机制锁机制来解决.
来看看银行取钱的例子
无处理状态:

- (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释放时,系统就会调度一个阻塞的线程来取钱了

同步代码块

- (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实现了大括号里的同步代码块,同时监听BlankAccount,其他线程需要获取到监听的BlankAccount才能被调度。

5、NSCondition有条件的多线程调度

NS_CLASS_AVAILABLE(10_5, 2_0)
@interface NSCondition : NSObject <NSLocking> {
@private
    void *_priv;
}

/*
调用NSCondition对象wait方法的线程会阻塞,直到其他线程调用该对象的signal方法或broadcast方法来唤醒
唤醒后该线程从阻塞态改为就绪态,交由系统进行线程调度
执行wait方法时内部会自动执行unlock方法释放锁,并阻塞线程
*/
- (void)wait;

//同上,只是该方法是在limit到达时唤醒线程
- (BOOL)waitUntilDate:(NSDate *)limit;

/*
唤醒在当前NSCondition对象上阻塞的一个线程
如果在该对象上wait的有多个线程则随机挑选一个,被挑选的线程则从阻塞态进入就绪态
*/
- (void)signal;

/*
同上,该方法会唤醒在当前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){
        /*
         这里一定要做同步操作,否则有概率导致被阻塞的线程无法被调起,可能是系统bug
         */
        if (_condition == nil) {
            _condition = [[NSCondition alloc]init];
        }
    }
    return _condition;
}

- (void)drawMoneyWithCondition:(NSNumber *)drawCash {
    //每个线程取钱20次
    
    NSInteger count = 0;
    while (count < 20) {
        //首先使用condition上锁,如果其他线程已经上锁则阻塞
        [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

线程调度:

- (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

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,444评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,421评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,363评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,460评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,502评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,511评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,280评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,736评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,014评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,190评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,848评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,531评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,159评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,411评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,067评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,078评论 2 352

推荐阅读更多精彩内容