美文网首页
NSThread使用介绍

NSThread使用介绍

作者: 嗨哒哥 | 来源:发表于2018-07-17 21:56 被阅读0次

    简介

    在iOS开发过程中,一共存在三种线程

    1、pthread,基本上不用
    2、Nsthread,面向对象,偶尔使用
    3、GCD,纯C语言,经常使用
    4、NSOpearation,是对GCD的封装,面向对象,经常使用
    

    在本篇的介绍中,我们着重介绍NSThread的使用

    NSThread创建

    一个NSthread就是一个单独的独立线程
    NSthread的创建一共可以分为如下三种方式:
    创建方式一:

    
        //创建线程的第一种方法,此种方式创建的线程不会自启动,需要调用start来启动线程
    //    NSThread *thread = [[NSThread alloc] initWithBlock:<#^(void)block#>];这种方式创建的线程的执行代码直接放在代码块里面执行
        
        //先创建对象,然后调用perform的一系列方法,也能执行线程的执行
    //    NSThread *thread = [[NSThread alloc] init];
    //    [thread performSelectorInBackground:<#(nonnull SEL)#> withObject:<#(nullable id)#>];
    //    [thread performSelectorOnMainThread:<#(nonnull SEL)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>];
    //    [thread performSelector:<#(SEL)#> withObject:<#(id)#>];
    //    [thread performSelector:<#(nonnull SEL)#> withObject:<#(nullable id)#> afterDelay:<#(NSTimeInterval)#>];
    //    [thread performSelector:<#(nonnull SEL)#> onThread:<#(nonnull NSThread *)#> withObject:<#(nullable id)#> waitUntilDone:<#(BOOL)#>];
        
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun) object:nil];
        [thread start];//启动线程
    

    创建方式二:

    - (void) createNSThread2 {
        //创建线程的第二种方法,使用此种方法创建的线程会自启动
    //    [NSThread detachNewThreadWithBlock:<#^(void)block#>];
        [NSThread detachNewThreadSelector:@selector(threadRun) toTarget:self withObject:nil];
    }
    

    创建方式三:

    - (void) createNSThread3 {
        //创建线程的第三种方式,隐试的创建线程
    //    [self performSelector:@selector(threadRun) withObject:self afterDelay:0];afterDelay表示可以延时多长时间执行线程
    //    [self performSelectorOnMainThread:@selector(threadRun) withObject:self waitUntilDone:<#(BOOL)#>];waitUntilDone表示是否等待线程执行完再往下进行,会阻塞当前程序运行
    //    [self performSelectorInBackground:<#(nonnull SEL)#> withObject:<#(nullable id)#>];在后台运行线程,意味着开辟新线程
        [self performSelector:@selector(threadRun) withObject:self];
    }
    

    上述创建NSThread的三种方式在使用中最为常见,其中通过第一种创建的线程需要手动调用【thread start】来启动,其余两种创建NSThread线程的方式会自动启动,无需在手动启动线程。

    NSThread与调用方法之间通信

    如果在创建线程的时候想给调用方法传递参数,可以使用如下方式

    [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"https://xxxxx.jpg"];
    - (void)threadRun:(NSSTting *)url {
    }
    

    给线程设置名称和获取当前线程

    想要知道程序具体运行在哪个线程当中,或者需要获取当前程序运行的是什么线程;此时需要给线程设置名称

    NSThread  *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadRun:) object:@"https://xxxxx.jpg"];
    thread.name = @"xx线程";
    

    然后在调用线程的的方法中通过【NSThread currentThread】来显示当前线程的名称和当前线程的num id号

    线程安全

    在使用多线程的过程中,享受了线程带来的便捷,自然就要考虑线程带来的一些隐患,比如多个线程共同抢夺一块资源的时候,如何保证线程的安全性?
    这里我们模拟一下飞机卖票的情形,多个窗口同时卖票,会出现什么问题?

    self.thread1 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket_notsafe_model) object:nil];
        self.thread1.name = @"thread1";
        
        self.thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket_notsafe_model) object:nil];
        self.thread2.name = @"thread2";
        
        self.thread3 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket_notsafe_model) object:nil];
        self.thread3.name = @"thread3";
        
        self.thread4 = [[NSThread alloc] initWithTarget:self selector:@selector(saleTicket_notsafe_model) object:nil];
        self.thread4.name = @"thread4";
        
        //开启线程
        [self.thread1 start];
        [self.thread2 start];
        [self.thread3 start];
        [self.thread4 start];
    
    while (true) {
            if (self.ticket_counts > 0) {
                self.ticket_counts -= 1;
                NSLog(@"thread.name----%@       tickets_left-------%d",[NSThread currentThread].name, self.ticket_counts);
            } else {
                return;
            }
        }
    

    此时就是造成线程对票数资源的抢夺,导致最终卖出去的票数不对,容易产生不必要的损失;面对这样的场景,我们可以使用加锁的方式来解决
    一种是使用NSLock

    首先声明一个所对象
    self.locker = [[NSObject alloc] init];
    然后再调用saleTicket的地方使用locker锁对象
    
    while (true) {
            @synchronized(self.lock) {
                if (self.ticket_counts > 0) {
                    self.ticket_counts -= 1;
                    NSLog(@"thread.name----%@       tickets_left-------%d",[NSThread currentThread].name, self.ticket_counts);
                } else {
                    return;
                }
            }
        }
    

    这里有一个需要注意的地方,就是NSLock必须使用的是同一个锁对象

    另外一种方法就是使用self加锁

    while (true) {
            @synchronized(self) {
                if (self.ticket_counts > 0) {
                    self.ticket_counts -= 1;
                    NSLog(@"thread.name----%@       tickets_left-------%d",[NSThread currentThread].name, self.ticket_counts);
                } else {
                    return;
                }
            }
        }
    

    最后附上以上代码链接

    上述所有代码均可以在NSThreadDemo中查看,有需要可以自行获取

    相关文章

      网友评论

          本文标题:NSThread使用介绍

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