天天看點

iOS個人整理32-多線程NSThread NSOperation

多線程

程式:由源代碼生成的可執行應用。

程序:一個正在運作的程式可用看做一個程序,程序擁有獨立運作所需要的全部資源。

線程:程式中獨立運作的代碼段

iOS5之後子線程也有重新整理UI的能力,但不夠快

iOS中關于UI的添加和重新整理必須在主線程中操作

使用多線程開發的優點:資源使用率更好,程式設計在某些情況下更簡單,程式響應更快

缺點:盡管提升了性能,但是存在一些通路限制,比如線程同步、線程互斥等,多線程在使用的時候,最終是要回到主線程重新整理UI,如果開辟過多的多線程,會造成CPU的消耗

一、NSThread

每個線程都維護着自己對應的NSAutoreleasePool對象,将其放線上程棧的棧頂。當線程結束時會情況自動釋放池

在應用程式打開的是,系統會自動為主線程建立一個自動釋放池

我們手動建立的子線程需要我們手動添加自動釋放池

//1.輕量級别的多線程實作方式
    //當使用alloc init方式,需要我們手動啟動,如果使用便利構造器的方法,不需要手動啟動
    //object 是線程回調方法的參數,不需要就寫nil
    NSThread *forThread = [[NSThread alloc]initWithTarget:self selector:@selector(aHundredMillion) object:nil];

    //通過便利構造器的方法建立Thread對象,不用手動啟動
    [NSThread detachNewThreadSelector:@selector(thread_1Action:) toTarget:self withObject:@"thread_1"];

    //為forThread命名    
    forThread.name = @"老二";
    
    //線程優先級,當優先級越高,線程被先執行的機率越高,0~1.0越來越高
    forThread.threadPriority = 1.0;
    
    //啟動線程
    [forThread start];
    
    //得到目前線程的資訊
    NSLog(@"iamgeThread--%@",[NSThread currentThread]);
    //得到主線程的資訊
    NSLog(@"%@",[NSThread mainThread]);

    //線程休眠
    [NSThread sleepForTimeInterval:2];

//結束線程
//1.給線程發結束消息
<p>[forThread cancel];</p>//2.了解結束線程
[NSThread exit];

//判斷線程是否在執行
[forThread isExecuting];

//判斷線程是否執行完畢
[forThread isFinished];

<p>NSObject的多線程方法</p><pre name="code" class="objc">   //1.從主線程進入子線程
    [self performSelectorInBackground:@selector(objectThreadAction:) withObject:@"object開的子線程"];
    
           
//NSObject進入子線程
-(void)objectThreadAction:(NSString*)sender
{
    NSLog(@"%@",sender);
    NSLog(@"%@",[NSThread currentThread]);
    //從子線程回到主線程
    //waitUnitDone:YES隻有回主線程的回調方法執行結束才會執行下面的操作。NO:與之相反
    [self performSelectorOnMainThread:@selector(backMainThread) withObject:nil waitUntilDone:YES];
    NSLog(@"在回到主線程的底下");
}

           

線程鎖

@property (nonatomic,retain)NSLock *myLock;//線程鎖,當多個線程同時通路同一資源的時候,對資源進行保護
@property (nonatomic,assign)int ticket_Sum;//線程直接跳的總數

@end

@implementation ViewController

-(NSLock *)myLock
{
    if (!_myLock) {
        _myLock = [[NSLock alloc]init];
    }
    return _myLock;
}

//線程鎖學習
-(void)lock_study
{
    @synchronized(self) {
        //線程鎖,保證目前隻有一個線程在通路該資源
        //将需要加鎖保護的代碼寫在花括号内
    }
    
    //當線程通路的是,加線程鎖
    [self.myLock lock];
    
    while (true) {
        if (_ticket_Sum > 0)
        {
            _ticket_Sum--;
            NSLog(@"剩餘票===  %d",_ticket_Sum);
        }
        else
        {
            break;
        }
    }
    
    //當正在執行的線程執行完操作的時候,解鎖。其他線程可以通路
    [self.myLock unlock];

}
           

二、NSOperation

NSOperation類,在MVC中屬于M,是用來封裝單個任務的相關代碼和資料的抽象類。

因為它是抽象的,不能直接使用這個類,而使用子類(NSInvocationOperation或NSBlockOperation)來執行任務。

NsOperation,隻是一個操作,本身無主線程子線程之分,可以在任意線程中使用,通常與NSOperationQueue結合使用

-(void)operation
{
    //初始化一個任務 target-action
    NSInvocationOperation *invocation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(invocationAction:) object:@"參數"];
    
    //當任務不在隊列中,需要手動啟動
    [invocation start];
       
    //操作block的方法
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        //實作我們需要做的操作
        NSLog(@"block  目前線程---%@",[NSThread currentThread]);
    }];
    
    //為block操作添加多個block執行
    //當使用addExecutionBlock添加可執行的block時,這些block會在目前線程或者其他子線程中進行
    for (int i = 0; i < 10; i++) {
        
        [blockOperation addExecutionBlock:^{
            NSLog(@"block2 目前線程-- %@",[NSThread currentThread]);
        }];
    }
    
    //最後執行的block,此block會在最後執行
    blockOperation.completionBlock = ^()
    {
        NSLog(@"最後執行的block-------%@",[NSThread currentThread]);
    };
    
    //all block must be before  start
    //啟動操作
    [blockOperation start];
    NSLog(@"我在最下面");
}
           

把任務加入隊列當中

//隊列quene  NSOperationQuene是對GCD的OC級别的封裝
-(void)operationQuene
{
    //先初始化隊列的對象,(其他隊列:出了主隊列,人為初始化的隊列都是其他隊列)
    NSOperationQueue *otherQuene = [[NSOperationQueue alloc]init];
    
    //設定最大并發數,預設為-1,可以無限個,設定為1的時候,在同一時刻隻能執行一個操作
    otherQuene.maxConcurrentOperationCount = 10;
    
    for (int i = 0; i < 10; i++) {
        //建立可執行的操作對象
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],i);
        }];
        
        if (i == 3) {
            
        }
        //将block操作添加到隊列中,當操作對象添加到隊列中之後,就不需要手動啟動了
        [otherQuene addOperation:blockOperation];
    }


    NSBlockOperation *blockOperation_0 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],0);
    }];
    NSBlockOperation *blockOperation_1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],1);
    }];
    NSBlockOperation *blockOperation_2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],2);
    }];
    NSBlockOperation *blockOperation_3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],3);
    }];
    NSBlockOperation *blockOperation_4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"隊列-----目前線程---%@--%d",[NSThread currentThread],4);
    }];
    
    //為事件添加依賴關系,第四個必須在第三個後面執行,這樣第四個任務一定在第三個執行後,才會執行
    //要先添加依賴再講事件添加到隊列
    [blockOperation_4 addDependency:blockOperation_3];
    
    //添加進隊列
    [otherQuene addOperation:blockOperation_0];
    [otherQuene addOperation:blockOperation_1];
    [otherQuene addOperation:blockOperation_2];
    [otherQuene addOperation:blockOperation_3];
    [otherQuene addOperation:blockOperation_4];
}
           

添加到主隊列

//主隊列
-(void)operationMainQuene
{
    
    NSLog(@"目前線程--與主隊列無關--%@",[NSThread currentThread]);
    
    NSOperationQueue *mainQuene = [NSOperationQueue mainQueue];
    for (int i = 0; i < 10; i++) {
        NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"主線程-----%@-------%d",[NSThread currentThread],i);
        }];
        [mainQuene addOperation:blockOperation];
    }
}
           

GCD 多線程優化 這個下一篇再說吧