iOS開發(fā)筆記-多線程的使用方法

多線程方式一:GCD
隊列的3個種類:

  1. 自建隊列: 分并行/串行
  2. 全局隊列: 屬于并行隊列, 是系統(tǒng)默認創(chuàng)建的.
  3. 主隊列: 主線程上的隊列. 串行隊列

1.自建隊列四種
異步:異于當(dāng)前方法所在線程 async
同步:同于當(dāng)前方法所在線程 sync
串行:任務(wù)按順序執(zhí)行 SERIAL
并行:任務(wù)沒有順序,同時執(zhí)行 CONCURRENT

switch (indexPath.section) {
        case 0: //異步串行
        {
            //隊列:任務(wù)是放在隊列中的
            //SERIAL串行,序列  CONCURRENT 并行
            dispatch_queue_t queue = dispatch_queue_create("串行", DISPATCH_QUEUE_SERIAL);
            //隊列放方法,并且規(guī)定方法在哪個線程中執(zhí)行
            //把參數(shù)2的方法放到參數(shù)1的隊列中,異步執(zhí)行
            dispatch_async(queue, ^{
                [self doMethod0];
            });
            dispatch_async(queue, ^{
                [self doMethod1];
            });
        }
            break;
        case 1: //異步并行
        {
            dispatch_queue_t queue = dispatch_queue_create("并行", DISPATCH_QUEUE_CONCURRENT);
            dispatch_async(queue, ^{
                [self doMethod0];
                //[self doMethod1];這樣寫,自然就串行了
            });
            dispatch_async(queue, ^{
                [self doMethod1];
            });
        }
            break;
        case 2://同步串行
        {
            [self doMethod0];
            [self doMethod1];
            return;
            dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL);
            dispatch_sync(queue, ^{
                [self doMethod0];
            });
            dispatch_sync(queue, ^{
                [self doMethod1];
            });
        }
            break;
        case 3: //同步并行
        {
            dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
            dispatch_sync(queue, ^{
                [self doMethod0];
            });
            dispatch_sync(queue, ^{
                [self doMethod1];
            });
        }
            break;
            
        default:
            break;
    }

2.全局隊列和主隊類

- (void)viewDidLoad {
    [super viewDidLoad];
    //dispatch_get_global_queue獲取全局隊列, 參數(shù)1代表優(yōu)先級, 0是默認優(yōu)先級. 參數(shù)2 無用
   dispatch_async(dispatch_get_global_queue(0, 0), ^{
       for (int i = 0; i < 10000; i++) {
           NSLog(@"%@, %d", [NSThread currentThread], i);
       }
       //dispatch_get_main_queue() 主隊列 嵌套在全局隊列中 與上方for循環(huán)屬于全局隊列中的一個任務(wù)所以是串行的
       dispatch_async(dispatch_get_main_queue(), ^{
          //所有與UIKit相關(guān)的操作一定要放到主線程中
           UIView *v = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];
           v.backgroundColor = [UIColor redColor];
           [self.view addSubview:v];
           v.center = self.view.center;
       });
   });
}

barrier(墻) 和分組

- (void)refreshImage{
    NSArray *imagePaths = @[@"http://imgstore.cdn.sogou.com/app/a/11220002/7291_pc.jpg", @"http://b.zol-img.com.cn/desk/bizhi/image/3/960x600/1376532627798.jpg", @"http://pic27.nipic.com/20130304/11627225_191300344144_2.jpg"];
    //barrier(墻): 墻必須加到自建隊列中.
    dispatch_queue_t queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT);
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [imagePaths enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSURL *url = [NSURL URLWithString:obj];
        dispatch_async(queue, ^{
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *img = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageViews[idx].image = img;
            });
        });
    }];
    //在自建的并行隊列中添加墻, 墻只有在并行隊列中的所有任務(wù)都執(zhí)行結(jié)束后, 才會被推倒
    dispatch_barrier_async(queue, ^{
        NSLog(@"%@", [NSThread currentThread]);
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    });
    
    return;
    //可以把多個子線程放到一個分組中, 通過監(jiān)聽此分組的情況來決定一些操作
    dispatch_group_t group = dispatch_group_create();
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;
    [imagePaths enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSURL *url = [NSURL URLWithString:obj];
        dispatch_group_async(group, dispatch_get_global_queue(0, 0), ^{
            NSData *data = [NSData dataWithContentsOfURL:url];
            UIImage *image = [UIImage imageWithData:data];
            dispatch_async(dispatch_get_main_queue(), ^{
                self.imageViews[idx].image = image;
            });
        });
    }];
    
    //監(jiān)聽分組中的線程都執(zhí)行結(jié)束的時機
    dispatch_group_notify(group, dispatch_get_global_queue(0, 0), ^{
        NSLog(@"%@", [NSThread currentThread]);
        [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
    });
    
    
}

死鎖

- (void)viewDidLoad {
    [super viewDidLoad];
    /*
     死鎖: 在`主線程` 中 調(diào)用 `dispatch_sync` 同步方法
     向 `主線程` 中放入一個任務(wù)
     
     dispatch_sync() will not return until the block has finished.
     dispatch_sync()這個方法直到block完成以后,才返回.
     
     下方的代碼是 向主線程中插入一個 block. 根據(jù)官方要求 必須是這個block執(zhí)行結(jié)束以后,dispatch_sync()方法才能執(zhí)行完畢.
     線程特點: 一個線程同時只能做一件事情, 多個任務(wù)是排隊執(zhí)行的.
     看主線程隊列: dispatch_sync()方法 -> 打印block方法
     dispatch_sync()的完成需要block方法執(zhí)行完畢.
     因為排隊問題 block 必須在 dispatch_sync() 執(zhí)行完畢后再進行!!!
     */
   
    /*
     面試問題:下方方法是否有什么問題?
     答: 有可能造成死鎖. 因為取決于這個方法執(zhí)行的線程, 只有在主線程才會死鎖.. 說下死鎖的三個關(guān)鍵點.
     */
    
    //dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_sync(dispatch_get_main_queue(), ^{
            NSLog(@".....");
        });
    //});
    
    //如果解決這個死鎖問題?
    //dispatch_async()方法不要內(nèi)部的block完成就可以完成
    dispatch_async(dispatch_get_main_queue(), ^{
        NSLog(@".....");
    });
    
    self.view.backgroundColor = [UIColor yellowColor];
    
    
}

多線程方式二:NSThread

- (void)redBtnClicked:sender{
    NSLog(@"redBtnClicked %@", [NSThread currentThread]);
    //在后臺線程執(zhí)行方法
    //[self performSelectorInBackground:@selector(wasteTime) withObject:nil];
    
    //方式2:
    //[NSThread detachNewThreadSelector:@selector(wasteTime) toTarget:self withObject:nil];
    
    //方式3:
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(wasteTime) object:nil];
    thread.name = @"1606";
    [thread start];//必須手動開啟
    
}
//開啟一個新的線程, 在線程中做耗時操作
- (void)wasteTime{
    //[NSThread currentThread]: 獲取當(dāng)前方法所在的線程
    //number=1 代表主線程, 其他都是子線程
    for (int i = 0; i < 10000; i++) {
        NSLog(@"%d , %@", i, [NSThread currentThread]);
    }

    //從子線程回歸主線程,規(guī)避掉線程不安全的操作
    [self performSelectorOnMainThread:@selector(changeUI) withObject:nil waitUntilDone:NO];
    //waitUntilDone:表示是否要等待changeUI這個方法執(zhí)行結(jié)束以后, 才繼續(xù)執(zhí)行下方代碼
    NSLog(@"--------------------");
}

多線程方式三:NSOperation
NSOperation 就是 使用OC語法 對 GCD做的封裝, 效率上略低(可以忽略不計), 繼續(xù)如何選擇 看個人喜好
NSOperationQueue : 隊列
NSOperation : 任務(wù)
任務(wù) 存放在 隊列 中, 隊列 存放在 線程

//NSOperation 封裝了GCD之后, 額外增加的易用方法
- (void)runMethod1{
    NSOperationQueue *queue = [NSOperationQueue new];
    
    NSBlockOperation *op0 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op0 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op0 結(jié)束, %@", [NSThread currentThread]);
    }];
    
    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op1 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op1 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op2 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op2 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op3 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op3 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op4 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op4 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op5 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op5 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op5 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op6 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op6 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op6 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op7 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op7 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op7 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op8 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op8 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op8 結(jié)束, %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op9 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"op9 開始, %@", [NSThread currentThread]);
        sleep(2);
        NSLog(@"op9 結(jié)束, %@", [NSThread currentThread]);
    }];
    //以為單線程CPU(硬件), 開啟多線程, 是偽多線程. 就是把cpu的線程分很多個時間片, 每個時間片做一件事. 因為速度太快了, 所以顯得跟多線程一樣.
    //最佳的線程數(shù)量是3~5個
    
    //NSOperatin就提供了最大并發(fā)數(shù)量的屬性, 此屬性必須在任務(wù)添加到隊列`之前`寫才有用!!
    queue.maxConcurrentOperationCount = 3;
    
    //規(guī)定線程依賴. 比如a必須等b線程做完才能進行
    //op0 必須等 op7 和 op9 執(zhí)行完畢 才能進行
    [op0 addDependency:op7];
    [op0 addDependency:op9];
    
    //任務(wù)添加到隊列中之后, 任務(wù)就會自動執(zhí)行
    //[queue addOperation:op0];
    //waitUntilFinished:參數(shù)表示,下方的打印方法是否要等待隊列中的任務(wù)執(zhí)行結(jié)束之后, 再運行
    [queue addOperations:@[op0, op1, op2, op3, op4, op5, op6, op7, op8, op9] waitUntilFinished:NO];
    NSLog(@"!@#$##$^^&^&$^@#$");
    
    
    //取消線程中的所有任務(wù): 已經(jīng)執(zhí)行的任務(wù)無法取消
    //[queue cancelAllOperations];
    
    //取消個別任務(wù)
    [op2 cancel]; //已經(jīng)執(zhí)行的取消不了
    [op9 cancel]; //0依賴9, 9被取消, 0就不再依賴9
    
    //暫停, 已經(jīng)運行的任務(wù) 無法暫停
    queue.suspended = YES;
    sleep(10);
    queue.suspended = NO;
}

//開子線程+回歸主線程
- (void)runMethod0{
    //[NSOperationQueue new] 自動開啟子線程
    [[NSOperationQueue new] addOperationWithBlock:^{
        NSLog(@"[NSOperationQueue new], %@", [NSThread currentThread]);
        //回歸主線程
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
           NSLog(@"[NSOperationQueue mainQueue], %@", [NSThread currentThread]);
        }];
    }];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 進程和線程 首先,在了解多線程之前要了解什么是進程,什么是線程 什么是進程呢?進程是指在系統(tǒng)中正在運行的一個應(yīng)用程...
    擱淺的青蛙閱讀 463評論 0 0
  • 對于多線程的理解:多線程: 利用多核處理器的優(yōu)勢,實現(xiàn)多個操作的并發(fā)執(zhí)行,使系統(tǒng)資源得到充分利用,提高運行效率,減...
    大猿媛閱讀 330評論 0 0
  • 從哪說起呢? 單純講多線程編程真的不知道從哪下嘴。。 不如我直接引用一個最簡單的問題,以這個作為切入點好了 在ma...
    Mr_Baymax閱讀 2,912評論 1 17
  • 背景 擔(dān)心了兩周的我終于輪到去醫(yī)院做胃鏡檢查了!去的時候我都想好了最壞的可能(胃癌),之前在網(wǎng)上查的癥狀都很相似。...
    Dely閱讀 9,402評論 21 42
  • 前言 iOS多線程有四種:pthread(最古老的),NSThread,NSOperation,GCD 一、進程和...
    GitHubPorter閱讀 407評論 0 3

友情鏈接更多精彩內(nèi)容