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線程有所了解。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM