1. 程式人生 > >iOS多執行緒的基本使用

iOS多執行緒的基本使用

一、NSThread:

程式就是一段程式碼,是靜態的概念

程序是執行起來的程式,是動態的概念,程序需要佔記憶體空間

執行緒是程序的基本單位,一個程序至少有一個執行緒,iOS程式預設有一個主執行緒,用來顯示和操作UI,主執行緒由系統自動建立,有系統管理。如果主執行緒不能滿足我們的需求,可以手動建立執行緒,手動建立的執行緒需要我們自己管理。

1.例:讓一個執行緒延遲10秒執行

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //按鈕一

    UIButton *btn1 = [MyUtilcreateBtnFrame:CGRectMake(100,10080,40title:@"按鈕一"bgImageName:niltarget:selfaction:@selector(clickBtnOne:)];

    [self.viewaddSubview:btn1];

    //按鈕二

    UIButton *btn2 = [MyUtilcreateBtnFrame:CGRectMake(100,20080,40title:@"按鈕二"bgImageName:niltarget:selfaction:@selector(clickBtnTwo:)];

    [self.viewaddSubview:btn2];

}

- (void)clickBtnOne:(id)sender

{

    //模擬耗時較長的操作

    //例如實際中的網路請求或者資料庫的操作

    //讓執行緒睡眠十秒

    [NSThreadsleepForTimeInterval:10];

    //如果不使用多執行緒,會有介面假死的現象

    //使用者體驗不好

    //所有在這種情況下我們需要使用多執行緒

}

- (void)clickBtnTwo:(id)sender

{

    NSLog(@"%s",__func__);

}


2.執行緒的優先順序:

//用執行緒的這個屬性來修改執行緒的優先順序,屬性值越大,執行的次數越多

   t1.threadPriority =0;

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //執行緒一

    NSThread *t1 = [[NSThreadallocinitWithTarget:selfselector:@selector(threadOne)object:nil];

    //修改優先順序

    //優先順序的值在0-1之間,優先順序越高,執行的次數相對來說會越多

    t1.threadPriority =0;

    [t1 start];

    //執行緒二

    NSThread *t2 = [[NSThreadallocinitWithTarget:selfselector:@selector(threadTwo)object:nil];

    //修改優先順序,線和二大於執行緒一,執行緒二先執行完成

    t2.threadPriority =1;

    [t2 start];

}

- (void)threadOne

{

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

        NSLog(@"執行緒一:%d", i);

    }

}

- (void)threadTwo

{

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

        NSLog(@"執行緒二:%d", i);

    }

}

3. 執行緒鎖:

第一種方法用: @synchronized加執行緒鎖

-(void)withDraw:(float)money

{

    //多個執行緒修改同一塊資源的時候,會出現問題

    //我們需要用執行緒鎖的方式解決

    @synchronized(self){

        if (_money >= money) {

            //模擬取錢的時間

            [NSThreadsleepForTimeInterval:1];

            _money -= money;

            NSLog(@"%@取了%f",[NSThreadcurrentThread].name,money);

        }else{

            NSLog(@"餘額不足");

        }

    }

}

@end

第二種方法:

用NSLock 來實現加鎖和解鎖

@implementation MyAccount

{

    //執行緒鎖

    NSLock *_myLock;

}

-(instancetype)init

{

    if (self = [superinit]) {

        _myLock = [[NSLockallocinit];

    }

    returnself;

}

-(void)withDraw:(float)money

{

    //多個執行緒修改同一塊資源的時候,會出現問題

    //我們需要用執行緒鎖的方式解決

    //加鎖

    [_myLocklock];

    if (_money >= money) {

        //模擬取錢的時間

        [NSThreadsleepForTimeInterval:1];

        _money -= money;

        NSLog(@"%@取了%f",[NSThreadcurrentThread].name,money);

    }else{

        NSLog(@"餘額不足");

    }

    //解鎖

    [_myLockunlock];

}

@end

二:NSOpreation:

1.用NSOpreation實現線上下載圖片

#import "ViewController.h"

#import "ImageOperation.h"

@interfaceViewController ()

{

    NSOperationQueue *_queue;

}

@end

@implementation ViewController

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //建立圖片檢視

    UIImageView *myImageView = [[UIImageViewallocinitWithFrame:CGRectMake(40,100300,300)];

    [self.viewaddSubview:myImageView];

    //使用NSOperatio自定製型別實現多執行緒

    //1.建立一個佇列

    _queue = [[NSOperationQueueallocinit];

    //佇列裡面同時執行的執行緒最大數量

    //例如往佇列裡面加了20個執行緒,只會執行10個,其他的執行緒要等這10箇中的某個執行完成之後,才能執行

    _queue.maxConcurrentOperationCount =10;

    //2.建立ImageOperation物件

    ImageOperation *op = [[ImageOperationallocinit];

    //設定下載連結

    op.urlString=@"http://g.hiphotos.baidu.com/image/pic/item/4034970a304e251fb3145e6ca586c9177e3e5346.jpg";

    //設定顯示的檢視

    op.imgView = myImageView;

    //新增到佇列

    [_queueaddOperation:op];

    //ASIHttpRequest: NSOperation

}

////////////////////////////////////////////////////////////////////////////////////////////////////////

#import "ImageOperation.h"

@implementation ImageOperation

//使用NSOperation自定製物件建立執行緒時的執行體

-(void)main

{

    //下載圖片

    NSURL *url = [NSURLURLWithString:self.urlString];

    NSData *data = [NSDatadataWithContentsOfURL:url];

    //回到主執行緒修改UI

    [selfperformSelectorOnMainThread:@selector(refreshUI:)withObject:data waitUntilDone:YES];

}

- (void)refreshUI:(NSData *)data

{

    self.imgView.image = [UIImageimageWithData:data];

}

@end

2.使用NSOperation建立多執行緒:

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //NSOperation實現多執行緒

    //1.建立佇列

    _queue = [[NSOperationQueueallocinit];

    //2.建立NSInvocationOperation物件

    /*

     第一個引數:執行緒執行體方法所屬的物件

     第二個引數:執行緒執行體方法

     第三個引數:執行緒執行體方法傳遞的實參

     */

    NSInvocationOperation *op1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(threadOne)object:nil];

    //執行緒結束之後執行的程式碼塊

    [op1 setCompletionBlock:^{

        NSLog(@"執行緒一結束");

    }];

    //3.開啟執行緒

    [_queueaddOperation:op1];

    //第二種實現執行緒的方式

    NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{

        //執行緒的執行體

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

            NSLog(@"執行執行緒二:%d",i);

        }

    }];

    //執行緒執行結束後呼叫的程式碼塊

    [op2 setCompletionBlock:^{

        NSLog(@"執行緒二結束");

    }];

    //新增到佇列裡面

    [_queueaddOperation:op2];

}

//執行緒執行體方法

- (void)threadOne

{

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

        NSLog(@"執行了執行緒一:%d", i);

    }

}

三:GCD:

1.用GCD實現多執行緒:

#import "ViewController.h"

@interfaceViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //1.同一塊程式碼執行多次

    //[self testApply];

    //2.程式碼只執行一次

//    [self testOnce];

//    [self testOnce];

//    [self testOnce];

//    [self testOnce];

    //3.在一段時間之後執行程式碼塊

    //[self testAfter];

    //4.執行緒組(group)

    //[self testGroup];

    //5.在某幾個執行緒都執行完成之後,並在另外幾個執行緒都執行完成之前,需要執行一些程式碼

    [selftestBarrier];

}

//5.在某幾個執行緒都執行完成之後,並在另外幾個執行緒都執行完成之前,需要執行一些程式碼

- (void)testBarrier

{

    //佇列不能是系統的全域性佇列

    dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

    //執行緒一

    dispatch_async(concurrentQueue, ^{

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

            NSLog(@"執行緒一:%d", i);

        }

    });

    //執行緒二

    dispatch_async(concurrentQueue, ^{

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

            NSLog(@"執行緒二:%d", i);

        }

    });

    //線上程一和執行緒二都執行完成之後,並且線上程三執行之前,呼叫一段程式碼塊

    dispatch_barrier_async(concurrentQueue, ^{

        NSLog(@"barrier");

    });

    //執行緒三

    dispatch_async(concurrentQueue, ^{

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

            NSLog(@"執行緒三:%d", i);

        }

    });

}

//4.多個執行緒都執行之後去執行一些程式碼

- (void)testGroup

{

    //執行緒組

    dispatch_group_t group =dispatch_group_create();

    /*

     第一個引數:執行緒組

     第二個引數:執行緒所在的佇列

     第三個引數:執行緒的執行體

     */

    dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

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

            NSLog(@"執行了執行緒一:%d", i);

        }

    });

    dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

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

            NSLog(@"執行了執行緒二:%d", i);

        }

    });

    //在該組的所有執行緒都執行結束時做執行某段程式碼

    dispatch_group_notify(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{

        NSLog(@"所有執行緒都執行完成");

    });

}

//3.在一段時間之後執行程式碼塊

- (void)testAfter

{

    NSLog(@"執行之前");

    //DISPATCH_TIME_NOW:表示當前的時間

    //當前時間的十秒之後

    dispatch_time_t myTime =dispatch_time(DISPATCH_TIME_NOW,NSEC_PER_SEC*10);

    //佇列

    //建立一個並行的佇列

    dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

    /*

     第一個引數:程式碼塊執行的時間

     第二個引數:程式碼塊的執行緒所在的佇列

     第三個引數:執行的程式碼塊

     */

    dispatch_after(myTime, concurrentQueue, ^{

        NSLog(@"執行了程式碼塊");

    });

}

//2.程式碼只執行一次

//通常用來實現單例

- (void)testOnce

{

    staticdispatch_once_t onceToken;

    dispatch_once(&onceToken, ^{

        NSLog(@"執行了一次");

    });

}

//1.同一塊程式碼執行多次

- (void)testApply

{

    /*

     第一個引數:程式碼塊執行多少次

     第二個引數:執行緒所在的佇列

     第三個引數:執行緒的執行體

     */

    dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    //引數表示當前是第幾次執行

    dispatch_apply(10, globalQueue, ^(size_t time) {

        //執行緒的執行體

        NSLog(@"執行到了第%ld", time);

    });

}

- (void)didReceiveMemoryWarning {

    [superdidReceiveMemoryWarning];

    // Dispose of any resources that can be recreated.

}

@end

2.GCD實現多執行緒2:

- (void)viewDidLoad {

    [superviewDidLoad];

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

    //GCD實現多執行緒

    //一、GCD的佇列

    //1.主執行緒所在的序列佇列

    //系統自動建立了這個佇列,我們只要獲取後使用

    dispatch_queue_t mainQueue =dispatch_get_main_queue();

    //2.系統的全域性並行佇列

    //系統自動建立了這個佇列,我們只能獲取後使用

    /*

     第一個引數:佇列的優先順序

     第二個引數:APPLE公司保留的引數

     */

    dispatch_queue_t globalQueue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    //3.自己建立的佇列

    //1)序列佇列

    /*

     第一個引數:佇列的識別符號

     第二個引數:用來區分是序列佇列還是並行佇列

     DISPATCH_QUEUE_SERIAL:序列佇列

     DISPATCH_QUEUE_CONCURRENT:並行佇列

     */

    dispatch_queue_t serialQueue =dispatch_queue_create("serialQueue",DISPATCH_QUEUE_SERIAL);

    //2)並行佇列

    dispatch_queue_t concurrentQueue =dispatch_queue_create("concurrentQueue",DISPATCH_QUEUE_CONCURRENT);

    //二、GCD建立執行緒

    //1、非同步將執行緒的執行體程式碼放到佇列執行

    /*

     第一個引數:佇列

     第二個引數:執行緒的執行體程式碼

     */

    dispatch_queue_t queueOne =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);

    dispatch_async(queueOne, ^{

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

            NSLog(@"執行了執行緒一:%d", i);

        }

    });

    //2、同步將執行緒的執行體放到佇列執行

    dispatch_sync(queueOne, ^{

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

            NSLog(@"執行了執行緒二:%d", i);

        }

    });

}

- (void)didReceiveMemoryWarning {

    [superdidReceiveMemoryWarning];