iOS多線程

多線程的概念不再贅述,iOS開發中總的來講可用的多線程方法一共有四種。

多線程的優點
能適當提高程序的執行效率
能適當提高資源利用率(CPU、內存利用率)


多線程的缺點
創建線程是有開銷的,iOS下主要成本包括:內核數據結構(大約1KB)、棧空間(子線程512KB、主線程1MB,也可以使用-setStackSize:設置,但必須是4K的倍數,而且最小是16K),創建線程大約需要90毫秒的創建時間
如果開啓大量的線程會降低程序的性能
線程越多,CPU在調度線程上的開銷就越大
程序設計更加複雜:比如線程之間的通信、多線程的數據共享

pthread

一套通用的多線程API
適用於Unix\Linux\Windows等系統
跨平臺\可移植
使用難度大

NSThread

面向對象,偶爾使用,需要手動管理生命週期,其實也只是需要你手動去開啓線程。

// 簡單用法

  // 創建線程

    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"jack"];

    thread.name = @"my-thread";

    // 啓動線程

    [thread start];


   [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"rose"];

// 消息傳遞

    [self performSelectorInBackground:@selector(run:) withObject:@"jack"];


  還有一些其他常用方法,具體不再贅述。


GCD

基於c語言,能夠充分利用設備的多核,具體方法如下

- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

    

    //GCD: 主要關注兩個內容

    // 同步執行, 異步執行;

    // 隊列:  主對列, 全局子隊列, 自定義隊列;

    

    //主隊列:

    dispatch_queue_t mainQueue = dispatch_get_main_queue(); // 獲取主隊列;


    //獲取全局子隊列:

    //優先級:

//    DISPATCH_QUEUE_PRIORITY_DEFAULT  默認優先級:

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    

#if 0

    // 在主對列發起同步任務, 主線程等待等待任務執行, 任務又在主線程裏面等待主線程,造成互相等待, 卡頓:

    // 在主隊列發起同步任務:

    dispatch_sync(mainQueue, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

#endif

    

   

#if 0

    // 在全局隊列發起同步任務:

    dispatch_sync(globalQueue, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

#endif

    

#if 0

    // 用於在子線程回到主線程執行:  (常用做法)  √

    dispatch_async(mainQueue, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

#endif

    

#if 0

    // 異步任務, 全局子隊列:  (用到)  √

    // 會開啓子線程執行任務:

    // 可以開啓多條子線程:

    dispatch_async(globalQueue, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    

    dispatch_async(globalQueue, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

#endif

    

#if 0

    // 參數二: 0 表示串行隊列:

    dispatch_queue_t customQueue1 = dispatch_queue_create("custom", 0);

    // 串行隊列只創建一條子線程,所有任務在這條線程裏串行執行:

    dispatch_async(customQueue1, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    dispatch_async(customQueue1, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

#endif


    // 參數二: DISPATCH_QUEUE_CONCURRENT 表示併發隊列:

    dispatch_queue_t customQueue2 = dispatch_queue_create("custom2", DISPATCH_QUEUE_CONCURRENT);

    // 併發隊列,可以開啓多條線程:

    dispatch_async(customQueue2, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    dispatch_async(customQueue2, ^{

        NSLog(@"%@", [NSThread currentThread]);

    });

    

    // 一段時間執行對應的代碼:

    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{

        UIAlertView *a = [[UIAlertView alloc] initWithTitle:@"彈框" message:nil delegate:nil cancelButtonTitle:nil otherButtonTitles:@"確定", nil];

        [a show];

    });

    NSLog(@".....");


    // 只會執行一次:

//    static dispatch_once_t onceToken;

//    dispatch_once(&onceToken, ^{

//        <#code to be executed once#>

//    });

//    [SingleExample shareSingle];

//    [[SingleExample alloc] init];

    

//    [[SingleExample alloc] init];

//    [UIApplication sharedApplication];

//    [NSNotificationCenter defaultCenter];

//    [NSFileManager defaultManager];

    NSLog(@"%p", [SingleExample shareSingle]);

    NSLog(@"%p", [SingleExample shareSingle]);

    NSLog(@"%p", [SingleExample shareSingle]);

//    NSLog(@"%p", [[SingleExample alloc] init]);

    

    

    // 分組執行任務:

    // 創建分組:

    dispatch_group_t group = dispatch_group_create();

    

    // 異步執行第一組任務:

    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"第一個任務%@", [NSThread currentThread]);

    });

    dispatch_group_async(group, globalQueue, ^{

        NSLog(@"第二個任務%@", [NSThread currentThread]);

    });


    // 等待其他任務執行完才執行:

    dispatch_group_notify(group, globalQueue, ^{

        NSLog(@"第三個任務%@", [NSThread currentThread]);

    });

    

    [NSThread detachNewThreadSelector:@selector(doSomeThing:) toTarget:self withObject:nil];

}


- (void)doSomeThing:(id)obj

{

    // 下載網絡數據:

    // 返回主線程刷新UI界面:

    dispatch_async(dispatch_get_main_queue(), ^{

        NSLog(@"refreshUI%@", [NSThread currentThread]);

    });

}


單粒寫法

static SingleExample *single = nil;


@implementation SingleExample


+ (SingleExample *)shareSingle

{

    static dispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        single = [[SingleExample alloc] init];

    });

    return single;

}




NSOperation

基於GCD(底層是GCD)
比GCD多了一些更簡單實用的功能
使用更加面向對象

代碼如下

@interface ViewController ()


// 線程隊列, 也稱爲線程池;

@property (nonatomic, strong) NSOperationQueue *queue;


@end


@implementation ViewController


- (NSOperationQueue *)queue

{

    if (_queue == nil) {

        _queue = [[NSOperationQueue alloc] init];

    }

    return _queue

}


- (void)viewDidLoad {

    [super viewDidLoad];

    // Do any additional setup after loading the view, typically from a nib.

}



- (void)doOp1:(id)obj

{

    for (int i = 0; i < 5; i++) {

        NSLog(@"op1");

        [NSThread sleepForTimeInterval:1.0];

    }

}


- (IBAction)clickStart:(id)sender {

//    NSOperation 的子類

    // 通過方法創建任務:

    // 執行方法裏面的代碼:

    NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doOp1:) object:nil];

    

    // 通過block方法創建任務:

    // 執行block裏面的代碼:

    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"op2");

    }];


    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"op3");

    }];

    // 最大的線程個數:

//    self.queue.maxConcurrentOperationCount = 1;  // 串行執行;

    //依賴順序關係:

    [op2 addDependency:op1];  // op2等待op1執行完才執行;

    [op3 addDependency:op1];  // op3等待op1執行完才執行;

                             // op2op3  op1 串行;

                             // op2op3 併發執行

    // 把任務放到線程隊列裏:

    [self.queue addOperation:op3];

    [self.queue addOperation:op2];

    [self.queue addOperation:op1];

//    [op1 cancel];

}



- (IBAction)clickStop:(id)sender {

    // 取消正在等待的任務:

    [self.queue cancelAllOperations];

}




@end



下面說下線程安全
在某些情況下,如果多個子線程同時訪問同一個方法或者變量,就會導致信息錯誤,比如數據覆蓋混亂等,那麼在這種情況下就需要設置線程鎖。

線程鎖就是鎖住線程,他會等上一個子線程進入並執行完操作之後,下一個子線程纔會進來執行操作,如果是成員變量的話,一般使用原子性,即natomic,如果是方法函數,則有兩種方法

一是NSLOCK
創建NSLOCK 

 NSLock *lock = [[NSLock alloc] init];

//加鎖

    [lock lock];

// 中間是訪問的方法

    // method

//解鎖

    [lock unlock];


第二種就是關鍵字synchronized 

示例方法

while (1) {

        @synchronized(self) {

           // method

        }

    }



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章