美文网首页
iOS多线程-NSthread

iOS多线程-NSthread

作者: rainbowboy | 来源:发表于2018-08-23 15:31 被阅读8次

    祭出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

    相关文章

      网友评论

          本文标题:iOS多线程-NSthread

          本文链接:https://www.haomeiwen.com/subject/uqlyiftx.html