NSThread使用介绍

简介

在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使用介绍)