iOS之多線程---三種多線程技術

1.多線程的基本概念和用法
①進程:每一個進程都一是一個應用程序,都有獨立的內存空間。(一個程序也可以由多個進程)同一個進程中的線程共享內存中的存儲空間和資源
②線程:
每一個程序都有一個主線程,調用main來啓動。
主線程的生命週期和應用程序綁定,程序退出時主線程停止。
任何可以阻塞主線程的任務不要再主線程中執行(比如訪問網絡)

2.多線程使用的注意
①線程使用不是無節制的:
iOS中的主線程的堆棧大小是1M(不可變)
從第二個線程開始都是512KB(不可變)
②只有主線程可以修改UI,渲染引擎工作在主線程中

3.IOS的三種多線程技術(本文主題)

①NSThread:每個NSThread對象對應一個線程
優:量級較輕
缺:需要自己管理線程的生命週期、線程同步、加鎖、睡眠和喚醒等,
②NSOperation/NSOperationQueue:面向對象的線程技術
優:不需要關心線程管理、數據同步的事情,且是面向對象的
③GCD(Grand Central Dispatch):是基於C語言的框架,可以充分利用多核,是蘋果推薦使用的多線程技術

下面對三種技術,用代碼逐一講解:

①NSThread

- (void)viewDidLoad {
    [super viewDidLoad];

    for (int i=0; i<10; i++) {
        //1.線程睡眠
        [NSThread sleepForTimeInterval:1];
        NSLog(@"主線程1: %d", i);
    }

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(thread1:) object:@"multiThread1"];
    //2.開始線程
    [thread start];

    for (int i=0; i<10; i++) {
        //3.獲取當前線程
        NSThread *current = [NSThread currentThread];
        //4.判斷當前線程是否是主線程
        BOOL isMain = [current isMainThread];
        if (isMain) {
            NSLog(@"主線程2: %d", i);
        }
    }
}

-(void) thread1:(NSString *) threadName{
    for (int i=0; i<10; i++) {
        NSLog(@"%@: %d", threadName, i);
        if (i == 5) {
            //5.退出線程
            [NSThread exit];
        }
    }
}

②NSOperationQueue

- (void)viewDidLoad {
    [super viewDidLoad];

    //1.創建線程隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    //2.創建線程任務
    /*NSOperation介紹:
    是Cocoa中的一個抽象類,用來封裝單個任務和代碼執行一項操作,由於是抽象類,所以不能直接實例化使用,必須定義子類繼承該抽象類來實現(常用的爲NSInvocationOperation類,但是也可以自己繼承重寫NSOperation類)
     */
    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread1:) object:@"thread1"];
    NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(thread2:) object:@"thread2"];

    //3.設置隊列屬性
        //1)設置併發數量
    queue.maxConcurrentOperationCount = 1;

        //2)暫停線程
    queue.suspended = YES;

        //3)設置線程優先級,需要先暫停線程纔會生效
    op1.queuePriority = NSOperationQueuePriorityHigh;
    op2.queuePriority = NSOperationQueuePriorityVeryLow;

    //4.任務完成時調用block
    op1.completionBlock = ^{
        NSLog(@"op1已經完成");
    };

    //5.創建任務的另一種方法:block方式
    [queue addOperationWithBlock:^{
        //也是一個線程入口,和op1、op2一樣是一個線程
        for (int k=0; k<10; k++) {
            NSLog(@"blockThread: %d", k);
        }
    }];

    [queue addOperation:op2];
    [queue addOperation:op1];

    //6.開始線程
    queue.suspended = NO;

    for (int k=0; k<10; k++) {
        NSLog(@"main: %i", k);
    }


}

-(void) thread1:(NSString *) threadName {
    for (int i=0; i<10; i++) {
        NSLog(@"%@: %d", threadName, i);
    }
}

-(void) thread2:(NSString *) threadName {
    for (int j=0; j<10; j++) {
        NSLog(@"%@: %d", threadName, j);
    }
}

③GCD

傳送門:http://blog.csdn.net/u012526801/article/details/49004871

補充1:線程中的內存管理問題,NSRunloop和如何跳出線程

NSRunloop:
①線程的生命週期存在5個狀態:新建、就緒、運行、阻塞、死亡
②NSRunLoop可以保持一個線程一直爲活動狀態,不會馬上銷燬掉
③應用舉例:多線程中使用定時器時,必須使用Runloop。因爲只有開啓Runloop保持線程爲活動狀態,定時器纔不會失效

跳出線程方法:
調用cancel方法,然後再線程方法中根據線程的isCancelled屬性可以break出線程方法
①跳出單個線程:[thread1 cancel];
②隊列中,跳出多個線程:[queue cancelAllOperations];

內存問題:
多線程創建的實例對象不會放入自動釋放池,可能會導致內存泄露。需要手動放入自動重生池

舉例:創建一個線程隊列queue和一個線程類MyOperation,在queue中添加2個繼承於MyOperation類的任務,實現以上補充內容中提到的知識點

以下是viewController中的代碼:

- (void)viewDidLoad {
    [super viewDidLoad];

    _queue = [[NSOperationQueue alloc] init];
    _op1 = [[MyOperation alloc] initwithName:@"thread1"];
    _op2 = [[MyOperation alloc] initwithName:@"thread2"];

    [_queue addOperation:_op1];
    [_queue addOperation:_op2];

    _op1.completionBlock = ^ {
        NSLog(@"op1已經完成------------------");
    };

    _op2.completionBlock = ^ {
        NSLog(@"op2已經完成------------------");
    };

//    [self performSelector:@selector(afterDelay) withObject:nil afterDelay:0.1];
    [self performSelector:@selector(cancelAllThread) withObject:nil afterDelay:0.5];
}

-(void) afterDelay {
    [_op1 cancel];
}

-(void) cancelAllThread {
    [_queue cancelAllOperations];
}

以下是MyOperation類的具體實現:

#import <Foundation/Foundation.h>

@interface MyOperation : NSOperation
@property (nonatomic, copy) NSString *mask;

-(instancetype) initwithName:(NSString *)mask;
@end

//##############################################################

#import "MyOperation.h"

@implementation MyOperation

-(instancetype) initwithName:(NSString *)mask {
    if (self == [super init]) {
        _mask = mask;
    }
    return self;
}

-(void) main {
    //1.多線程創建的實例對象不會放入自動釋放池,可能會導致內存泄露。需要手動放入自動重生池
    @autoreleasepool {

        [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timeAction) userInfo:nil repeats:YES];
        //2.開啓Runloop來保持線程的存活狀態
        [[NSRunLoop currentRunLoop] run];


        for (int i=0; i<1000; i++) {
            //3.cancel方法只是改變isCancelled屬性,在線程實現方法中做判斷,用於跳出線程方法。
            if (self.isCancelled) {
                break;
            }
            NSLog(@"%@: %d", self.mask, i);
        }
    }
}
-(void) timeAction {
}
@end
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章