IOS任务管理之NSThread使用

前言:

    无论是Android还是IOS都会使用到多任务,多任务的最小单元那就是线程,今天学习总结一下IOS的NSThread使用。

NSThread使用?

  第一种方式实例化

//selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
//target  :selector消息发送的对象
//argument:传输给target的唯一参数,也可以是nil
NSThread  *newThread = [[NSThread alloc]initWithTarget:self selector:@selector(threadRun) object:nil];

也可以使用另外两种初始化函数

NSThread  *newThread=[[NSThread alloc]init];
NSThread  *newThread= [[NSThread alloc]initWithBlock:^{
        NSLog(@"initWithBlock");
    }];

线程常用的一些属性

    //设置线程名字
    [newThread setName:@"thread - 1"];
    //设置线程优先级
    [newThread setThreadPriority:1.0];
    //IOS 8 之后 推荐使用下面这种方式设置线程优先级
    //NSQualityOfServiceUserInteractive:最高优先级,用于用户交互事件
    //NSQualityOfServiceUserInitiated:次高优先级,用于用户需要马上执行的事件
    //NSQualityOfServiceDefault:默认优先级,主线程和没有设置优先级的线程都默认为这个优先级
    //NSQualityOfServiceUtility:普通优先级,用于普通任务
    //NSQualityOfServiceBackground:最低优先级,用于不重要的任务
    [newThread setQualityOfService:NSQualityOfServiceUtility];
    //判断线程是否是主线程
    [newThread isMainThread];
    //线程状态
    //是否已经取消
    [newThread isCancelled];
    //是否已经结束
    [newThread isFinished];
    //是否正在执行
    [newThread isExecuting];

线程启动、取消、暂停

    //线程开始
    [newThread start];
    //线程取消
    [newThread cancel];
    //线程暂停
    [NSThread sleepForTimeInterval:1.0];
    //或者下面这种方式 让线程休眠1秒
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]];
    //立即终止除主线程以外所有线程
    [NSThread exit];

第二种方式类方法

//selector :线程执行的方法,这个selector只能有一个参数,而且不能有返回值。
//target  :selector消息发送的对象
//argument:传输给target的唯一参数,也可以是nil
[NSThread detachNewThreadSelector:@selector(doSomething:) toTarget:self withObject:@"lcj"];

上面这种方式创建线程后自动启动线程

 获取当前线程

[NSThread currentThread];

获取主线程

 [NSThread mainThread];

第三种方式隐式创建

  用于线程之间通信,比如:指定任务在当前线程执行

 //不传递参数指定函数在当前线程执行
 [self performSelector:@selector(doSomething)];
 //传递参数指定函数在当前线程执行
 [self performSelector: @selector(doSomething:) withObject:tempStr];
 //传递参数指定函数2秒后在当前线程执行
 [self performSelector:@selector(doSomething:) withObject:tempStr afterDelay:2.0];

指定在特定线程执行

//在其他线程中指定在主线程执行
[self performSelectorOnMainThread:@selector(doSomething:) withObject:tempStr waitUntilDone:YES];
//在主线程指定在后台线程执行
[self performSelectorInBackground:@selector(doSomething:) withObject:tempStr];
//在主线程中指定某个特定线程执行
[self performSelector:@selector(doSomething:)  onThread:newThread withObject:tempStr waitUntilDone:YES];

线程同步

  线程同步就是为了解决多线程同时访问公共共享数据,而导致数据错乱的问题,然后使用同步的方式让公共数据同一时间内只能被一个线程访问来避免数据错乱的问题。

先看下未同步时多线程访问数据错乱问题,首先声明三个线程

    NSThread *thread1=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun) object:nil];
    thread1.name=@"thread-1";
    
    NSThread *thread2=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun) object:nil];
    thread2.name=@"thread-2";
    
    NSThread *thread3=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun) object:nil];
    thread3.name=@"thread-3";
    
    [thread1 start];
    [thread2 start];
    [thread3 start];

taskRun函数对全部变量count进行操作

-(void)taskRun
{
    while (count>0) {
        [NSThread sleepForTimeInterval:0.1];
        count--;
        NSLog(@"threadName:%@ count:%d ",[NSThread currentThread].name, count);
    }
}

运行结果:

通过上面的数据会发现有明显的错乱问题,导致数据不同步。

实现线程同步的几种方式:

第一种方式@synchronized(对象)关键字

-(void)taskRun
{
    while (count>0) {
        @synchronized(self) { // 需要锁定的代码
            [NSThread sleepForTimeInterval:0.1];
            count--;
            NSLog(@"threadName:%@ count:%d ",[NSThread currentThread].name, count);
        }
    }
    
}

执行结果

第二种方式NSLock同步锁

首先创建一个NSLock同步锁对象

threadLock=[[NSLock alloc]init];

然后在需要加锁的代码块开始时调用 lock函数 在结束时调用unLock函数

-(void)taskRun
{

    while (count>0) {
        [threadLock lock];
        [NSThread sleepForTimeInterval:0.1];
        count--;
        NSLog(@"threadName:%@ count:%d ",[NSThread currentThread].name, count);
    }
    [threadLock unlock];
}

第三种方式使用NSCondition同步锁和线程检查器

  锁主要为了当检测条件时保护数据源,执行条件引发的任务;线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞。先创建一个NSCondition对象

condition=[[NSCondition alloc]init];

使用同步锁的方式和NSLock相似

-(void)taskRun
{
    
    while (count>0) {
        [condition lock];
        [NSThread sleepForTimeInterval:0.1];
        count--;
        NSLog(@"threadName:%@ count:%d ",[NSThread currentThread].name, count);
        [condition unlock];
    }
    
}

NSCondition可以让线程进行等待,然后获取到CPU发信号告诉线程不用在等待,可以继续执行,上述的例子我们稍作修改,我们让线程三专门用于发送信号源
 NSThread *thread1=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun) object:nil];
    thread1.name=@"thread-1";
    
    NSThread *thread2=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun) object:nil];
    thread2.name=@"thread-2";
    
    NSThread *thread3=[[NSThread alloc]initWithTarget:self selector:@selector(taskRun1) object:nil];
    thread3.name=@"thread-3";
    
    [thread1 start];
    [thread2 start];
    [thread3 start];

taskRun1函数用于发送信号源

-(void)taskRun1
{
    while (YES) {
        [condition lock];
        [NSThread sleepForTimeInterval:2];
        [condition signal];
        [condition unlock];
    }
}

taskRun函数 用于执行对count的操作

-(void)taskRun
{
    
    while (count>0) {
        [condition lock];
        [condition wait];
        [NSThread sleepForTimeInterval:0.1];
        count--;
        NSLog(@"threadName:%@ count:%d ",[NSThread currentThread].name, count);
        [condition unlock];
    }
    
}

执行的结果会发现,只有在Thread-1、和Thread-2 收到信号源的时候才会执行count--,否则一直出于等待状态。

总结:

   NSThread属于轻量级多任务实现方式,可以更加只管的管理线程,需要管理线程的生命周期、同步、加锁问题,会导致一定的性能开销,今天简单的了解学习了IOS的NSThread使用,初步对ios线程有所了解。

 

posted on 2017-02-14 11:55  总李写代码  阅读(4072)  评论(0编辑  收藏  举报