iOS-多線程(NSThread+GCD+NSOperation)

一、基本概念

  1. 進程:系統(tǒng)中正在運行的應(yīng)用程序。每個程序都是相互獨立的,并且運行在一塊獨有的受保護的內(nèi)存中
  2. 線程:進程基本執(zhí)行路徑。一個進程想要執(zhí)行任務(wù),就必須通過線程來執(zhí)行。單條的線程通過串行的方式執(zhí)行任務(wù),也就是說任務(wù)是一個一個按順序的執(zhí)行
  3. 多線程:開啟多條線程,讓任務(wù)并發(fā)執(zhí)行。(原理:在同一時間內(nèi),CPU 只會處理一條線程,多線程并發(fā)執(zhí)行其實是,cpu在不同的線程之間快速的切換處理,只要cpu切換的足夠快,就會給人多線程并發(fā)執(zhí)行任務(wù)的假象)
    補充:并行指的是任務(wù)一起執(zhí)行,強調(diào)的是過程;并發(fā)指的是任務(wù)以一起執(zhí)行的方式開始執(zhí)行,強調(diào)的是任務(wù)開始執(zhí)行的方式。

二、多線程的優(yōu)缺點

優(yōu)點
  1. 可提高程序的執(zhí)行效率
  2. 可合理提高cpu和內(nèi)存的利用率
缺點
  1. 開啟一條線程所占用的內(nèi)存較大(主線程 1M ;子線程 512KB)
  2. 線程多時,cpu在在切換線程上的開銷較大,影響性能
  3. 線程間的通訊和數(shù)據(jù)共享等會將大程序設(shè)計的復雜度

三、多線程的實現(xiàn)方案

1. NSThread

此方案是經(jīng)過蘋果封裝后完全面向?qū)ο蟮?,可以直接拿到線程對象進行操作,很直觀、便捷。但是缺點就是需手動管理線程生命周期,所以不經(jīng)常使用
1.1 創(chuàng)建(3種方式)

//  1.手動啟動線程,可拿到線程對象進行額外的設(shè)置
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
    [thread start];
    
    //  2.分離出子線程 - 自動啟動線程
    [NSThread detachNewThreadSelector:@selector(addChildThread:) toTarget:self withObject:@"子線程"];
    
    //  3.后臺線程 - 自動啟動線程
    [self performSelectorInBackground:@selector(addBackgroundThread:) withObject:@"后臺線程"];

1.2 NSThread 常涉及到的方法

    [thread cancel];  //取消線程
    [NSThread exit];
    [NSThread sleepForTimeInterval:3.0];  //阻塞線程
    [NSThread sleepUntilDate:[NSDate dateWithTimeIntervalSinceNow:3.0]];
    [NSThread currentThread];  //獲取當前線程
    [NSThread mainThread];  //獲取主線程
    [NSThread isMultiThreaded];  //是否是多線程,返回BOOL值

1.3 線程間通信

- (void)viewDidLoad {
    [super viewDidLoad];

    //  創(chuàng)建子線程
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(addThread:) object:@"hahaha"];
    [thread start];
}

- (void)addThread:(NSString *)name {
    NSLog(@"%@",[NSThread currentThread]);
    
    //  在子線程中回到主線程的兩種方式
    [self performSelectorOnMainThread:@selector(goBackMainThread:) withObject:@"main" waitUntilDone:YES];
    [self performSelector:@selector(goBackMainThread:) onThread:[NSThread mainThread] withObject:@"test" waitUntilDone:YES];
}

- (void)goBackMainThread:(NSString *)name {
    NSLog(@"%@",[NSThread currentThread]);
}

打印結(jié)果

2016-08-01 14:20:30.253 demo[66988:3541822] <NSThread: 0x79e71ab0>{number = 2, name = (null)}
2016-08-01 14:20:30.258 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}
2016-08-01 14:20:30.259 demo[66988:3541733] <NSThread: 0x79e72a30>{number = 1, name = main}

1.4 線程安全
當多個線程訪問同一塊資源時會發(fā)生數(shù)據(jù)安全問題,也稱為線程同步 ,這時候就需要加互斥鎖 @synchronized(self){}

2. GCD

蘋果為多核并行運算開發(fā)的解決方案,它可以自動的利用cpu的內(nèi)核,并且系統(tǒng)自動管理線程的生命周期
開發(fā)者要做的是將任務(wù)添加到隊列中,系統(tǒng)會自動將隊列中的任務(wù)按FIFO的原則取出任務(wù)(FIFO:先進先出,后進后出,如果以并發(fā)方式執(zhí)行任務(wù),則先出的任務(wù)還沒結(jié)束前下一個的任務(wù)可以出列)

2.1 任務(wù)和隊列的理解
任務(wù):決定能不能開啟新線程,分同步和異步任務(wù)兩種

-同步:任務(wù)只能在當前的線程執(zhí)行,不具備開啟新線程的能力(同步任務(wù)比較霸道,必須在當前的分配任務(wù)執(zhí)行完,才算把分配任務(wù)的任務(wù)結(jié)束,和后面說的死鎖有關(guān)聯(lián))
-異步:任務(wù)可以在其它線程中執(zhí)行,具備有開啟新線程的能力

    //  同步任務(wù)
    dispatch_sync(dispatch_get_global_queue(0, 0), ^{
    });
    //  異步任務(wù)
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
    });
隊列:決定任務(wù)將以什么方式執(zhí)行,分串行和并發(fā)隊列兩種

-串行:任務(wù)將一個接一個的執(zhí)行(一個任務(wù)執(zhí)行完才開始下一個任務(wù))
-并發(fā):多個任務(wù)可以并發(fā)(同時)執(zhí)行,要在異步任務(wù)函數(shù)中才能有效

隊列的創(chuàng)建

-串行:系統(tǒng)提供兩種方式

    //  1.系統(tǒng)提供的主隊列
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    //  2.創(chuàng)建新的串行隊列(參數(shù)1:隊列名字,apple推薦使用com.example.myQueue的規(guī)則來命名隊列,用于debug的時候追蹤隊列以便于調(diào)試,可以為空;
    //    參數(shù)2:可以傳人NULL或DISPATCH_QUEUE_SERIAL表示串行隊列)
    dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", NULL);

- 并發(fā):系統(tǒng)提供兩種方式

    //  1.系統(tǒng)提供的全局隊列(參數(shù)1:隊列的優(yōu)先級;參數(shù)2:傳0即可)
    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    //  2.創(chuàng)建新的并發(fā)隊列
    dispatch_queue_t queue = dispatch_queue_create("com.hhh.eatShit", DISPATCH_QUEUE_CONCURRENT);
2.2 GCD使用方式(任務(wù)和隊列的結(jié)合方式)
  1. 異步任務(wù)+并發(fā)隊列:使用頻率高,開啟多線程并發(fā)的執(zhí)行任務(wù)
  2. 異步任務(wù)+串行隊列:使用頻率高,開啟一條新線程,串行執(zhí)行任務(wù)
  3. 同步任務(wù)+并發(fā)隊列:基本不用,不開線程在當前線程串行執(zhí)行任務(wù)我
  4. 同步任務(wù)+串行隊列:基本不用,不開線程在當前線程串行執(zhí)行任務(wù)我
  5. 異步任務(wù)+主隊列:不開線程,在主線程中串行執(zhí)行任務(wù)我
  6. 同步任務(wù)+主隊列:不開線程,在主線程中串行執(zhí)行任務(wù)我(注意死鎖)
    注意:在當前的串行隊列中添加同步任務(wù)到當前隊列會發(fā)生死鎖
- (void)viewDidLoad {
    [super viewDidLoad];
    
    //  主隊列是串行的,在主隊里中往主隊列添加同步任務(wù),發(fā)生死鎖,無法執(zhí)行打印內(nèi)容
    dispatch_sync(dispatch_get_main_queue(), ^{
        NSLog(@"快把我打印出來");
    });
}
2.3 ??演示GCD的使用
  1. 異步任務(wù)+并發(fā)隊列
- (void)viewDidLoad {
    [super viewDidLoad];

    //  由系統(tǒng)決定開幾條線程
    dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
}

打印

2016-08-01 17:27:01.793 demo[79533:3667100] 任務(wù)1---<NSThread: 0x79858c40>{number = 2, name = (null)}
2016-08-01 17:27:01.793 demo[79533:3667104] 任務(wù)3---<NSThread: 0x7865da50>{number = 4, name = (null)}
2016-08-01 17:27:01.794 demo[79533:3667103] 任務(wù)2---<NSThread: 0x79a5a540>{number = 3, name = (null)}

2.異步任務(wù)+串行隊列

- (void)viewDidLoad {
    [super viewDidLoad];
    
    //  只開一條新線程
    dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
}

打印

2016-08-01 17:29:13.092 demo[79710:3669166] 任務(wù)1---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.093 demo[79710:3669166] 任務(wù)2---<NSThread: 0x7a236720>{number = 2, name = (null)}
2016-08-01 17:29:13.094 demo[79710:3669166] 任務(wù)3---<NSThread: 0x7a236720>{number = 2, name = (null)}

3.同步任務(wù)+并發(fā)隊列

- (void)viewDidLoad {
    [super viewDidLoad];

    //  不開新線程,當前是主線程,所以任務(wù)1、2、3在主線程中執(zhí)行
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
}

打印

2016-08-01 17:57:04.133 demo[81692:3691446] 任務(wù)1---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任務(wù)2---<NSThread: 0x7a2314b0>{number = 1, name = main}
2016-08-01 17:57:04.134 demo[81692:3691446] 任務(wù)3---<NSThread: 0x7a2314b0>{number = 1, name = main}

4.同步任務(wù)+串行隊列

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
    dispatch_async(queue, ^{
        NSLog(@"新開的子線程---%@",[NSThread currentThread]);

        //  在新開的子線程中,在queue隊列中測試
        dispatch_queue_t queue1 = dispatch_queue_create("com.demo.chuanxing", NULL);
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
        });
    });
}

打印

2016-08-01 17:53:10.405 demo[81376:3688029] 新開的子線程---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.406 demo[81376:3688029] 任務(wù)1---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任務(wù)2---<NSThread: 0x78e7fe80>{number = 2, name = (null)}
2016-08-01 17:53:10.407 demo[81376:3688029] 任務(wù)3---<NSThread: 0x78e7fe80>{number = 2, name = (null)}

5.異步任務(wù)+主隊列(同3)
6.同步任務(wù)+主隊列(切記不能在主隊列中使用這種方式)

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_queue_t queue = dispatch_queue_create("com.demo.chuanxing", NULL);
    dispatch_async(queue, ^{
        NSLog(@"新開的子線程---%@",[NSThread currentThread]);

        //  在新開的子線程中,任務(wù)1、2、3在主線程中執(zhí)行
        dispatch_queue_t queue1 = dispatch_get_main_queue();
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
        });
        dispatch_sync(queue1, ^{
            NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
        });
    });
}

打印

2016-08-01 17:59:57.794 demo[81900:3693593] 新開的子線程---<NSThread: 0x79745ab0>{number = 2, name = (null)}
2016-08-01 17:59:57.798 demo[81900:3693419] 任務(wù)1---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.799 demo[81900:3693419] 任務(wù)2---<NSThread: 0x79843a10>{number = 1, name = main}
2016-08-01 17:59:57.800 demo[81900:3693419] 任務(wù)3---<NSThread: 0x79843a10>{number = 1, name = main}
2.4 GCD其它函數(shù)
  1. 柵欄函數(shù) dispatch_barrier_async(queue, ^{ });
    在任務(wù)前面的異步任務(wù)都執(zhí)行完后才會執(zhí)行它,并且等它執(zhí)行完后,后面的異步任務(wù)才能開始執(zhí)行
    注意:
    1.>此函數(shù)加入全局隊列示無效的,即queue不能是全劇隊列
    2.>如果任務(wù)是同步的則會在當前的線程中執(zhí)行,異步的話在新線程中執(zhí)行

??

- (void)viewDidLoad {
    [super viewDidLoad];

    dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)7---%@",[NSThread currentThread]);
    });
}

打印(任務(wù)4總是在任務(wù)1、2、3和5、6、7的中間)

2016-08-01 20:55:44.075 demo[85715:3735784] 任務(wù)2---<NSThread: 0x7a8746e0>{number = 3, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735778] 任務(wù)1---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.075 demo[85715:3735777] 任務(wù)3---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.077 demo[85715:3735777] 任務(wù)4---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735777] 任務(wù)5---<NSThread: 0x7a67a470>{number = 4, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735778] 任務(wù)6---<NSThread: 0x7a96ff10>{number = 2, name = (null)}
2016-08-01 20:55:44.078 demo[85715:3735784] 任務(wù)7---<NSThread: 0x7a8746e0>{number = 3, name = (null)}

信號量的使用 --- 但以上任務(wù)2中存在其它異步并發(fā)任務(wù),如網(wǎng)絡(luò)請求的時:

   dispatch_queue_t queue = dispatch_queue_create("com.demo.bingfa", DISPATCH_QUEUE_CONCURRENT);
    
    dispatch_async(queue, ^{
       
        // 創(chuàng)建一個信號量為0的信號(紅燈)
        dispatch_semaphore_t sema = dispatch_semaphore_create(0);

        dispatch_queue_t queue2 = dispatch_queue_create("com.demo.bing", DISPATCH_QUEUE_CONCURRENT);

        dispatch_async(queue2, ^{
            [NSThread sleepForTimeInterval:2];
            // 使信號的信號量+1,這里的信號量本來為0,+1信號量為1(綠燈)
            dispatch_semaphore_signal(sema);
            NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
        });
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
        // 開啟信號等待,設(shè)置等待時間為永久,直到信號的信號量大于等于1(綠燈)
        dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
    });
    dispatch_async(queue, ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
    
    dispatch_barrier_async(queue, ^{
        NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
    });

2.隊列組
能實現(xiàn)在一個或則多個任務(wù)執(zhí)行完之后,在執(zhí)行特定的任務(wù)。例如:A任務(wù)和B任務(wù)并發(fā)執(zhí)行,C任務(wù)需要在A任務(wù)和B任務(wù)都執(zhí)行完之后再執(zhí)行,這時候就可以通過隊列組來實現(xiàn)
??

- (void)viewDidLoad {
    [super viewDidLoad];
    dispatch_group_t group = dispatch_group_create();
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
    });
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
    });
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"任務(wù)7---%@",[NSThread currentThread]);
    });
}

打印: 你會發(fā)現(xiàn)任務(wù)5永遠都是隊列組中最后執(zhí)行的一個

2016-08-01 22:10:55.218 demo[90162:3774195] 任務(wù)1---<NSThread: 0x7af959d0>{number = 2, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774194] 任務(wù)2---<NSThread: 0x7b1346f0>{number = 3, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774216] 任務(wù)6---<NSThread: 0x7b06cf00>{number = 6, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774215] 任務(wù)4---<NSThread: 0x7af95fe0>{number = 5, name = (null)}
2016-08-01 22:10:55.218 demo[90162:3774199] 任務(wù)3---<NSThread: 0x7ae30250>{number = 4, name = (null)}
2016-08-01 22:10:55.219 demo[90162:3774217] 任務(wù)7---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
2016-08-01 22:10:55.220 demo[90162:3774217] 任務(wù)5---<NSThread: 0x7b135bb0>{number = 7, name = (null)}
3.NSOperation
3.1 概念

NSOperation是對GCD的封裝;本身是一個抽象類,只能使用它的三個子類;和NSOperationQueue結(jié)合使用實現(xiàn)多線程并發(fā)

3.2 NSOperation和NSOperationQueue的理解
NSOperation三個子類

-NSInvocationOperation

- (void)viewDidLoad {
   [super viewDidLoad];
   //  不加入隊列執(zhí)行開始操作
   NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(addOperation:) object:@"NEW"];
   [operation start];
}
- (void)addOperation:(NSString *)name {
   //  在主線程中執(zhí)行,沒有意義
   NSLog(@"%@",[NSThread currentThread]);
}

-NSBlockOperation
創(chuàng)建操作時攜帶的任務(wù)在主線程,操作后面額外添加的任務(wù),系統(tǒng)自動開啟線程執(zhí)行

- (void)viewDidLoad {
    [super viewDidLoad];
    //  不加入隊列執(zhí)行開始操作
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        //  在主線程中執(zhí)行
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    }];
    [operation addExecutionBlock:^{
        //  系統(tǒng)根據(jù)需要自動開啟線程
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    }];
    [operation addExecutionBlock:^{
        //  系統(tǒng)根據(jù)需要自動開啟線程
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    }];
    [operation addExecutionBlock:^{
        //  系統(tǒng)根據(jù)需要自動開啟線程
        NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
    }];
    [operation start];
}

-自定義NSOperation
一般操作過于復雜時可以使用自定義NSOperation,具有隱蔽性和可重復利用的好處

#import "JYOperation.h"
@implementation JYOperation
- (void)main {
    NSLog(@"%@",[NSThread currentThread]);
}
@end
- (void)viewDidLoad {
    [super viewDidLoad];
    //  不添加到隊列的話,任務(wù)在主線程執(zhí)行,沒有意義
    JYOperation *operation = [[JYOperation alloc] init];
    [operation start];
}
NSOperationQueue

- 主隊列
添加到主隊列中的任務(wù)都在主線程中執(zhí)行
-非主隊列
任務(wù)在子線程中執(zhí)行,控制任務(wù)以串行或并發(fā)的方式執(zhí)行,具體通過設(shè)置隊列的maxConcurrentOperationCount(最大并發(fā)數(shù))屬性來控制

注意:

1.maxConcurrentOperationCount必須在操作添加到隊列之前設(shè)置才有效
2.maxConcurrentOperationCount 默認為-1,即默認任務(wù)是并發(fā)執(zhí)行;等于0時,不執(zhí)行任務(wù),無意義;等于1時,串行執(zhí)行任務(wù);等于n時,并發(fā)數(shù)為n,允許n個任務(wù)是同時執(zhí)行的

- (void)viewDidLoad {
    
    //  2.非主隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    queue.maxConcurrentOperationCount = 3;
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)3---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)4---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)5---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)6---%@",[NSThread currentThread]);
    }];
}

打印

2016-08-02 10:10:56.874 demo[99820:3887770] 任務(wù)1---<NSThread: 0x7a98b340>{number = 2, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887814] 任務(wù)3---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.874 demo[99820:3887769] 任務(wù)2---<NSThread: 0x7a71c450>{number = 3, name = (null)}
2016-08-02 10:10:56.875 demo[99820:3887814] 任務(wù)5---<NSThread: 0x7a71c690>{number = 4, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887810] 任務(wù)6---<NSThread: 0x7a71c840>{number = 5, name = (null)}
2016-08-02 10:10:56.876 demo[99820:3887770] 任務(wù)4---<NSThread: 0x7a98b340>{number = 2, name = (null)}
3.3 操作和隊列結(jié)合(兩種方式)
- (void)viewDidLoad {
    //  方式1:將操作加入隊列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任務(wù)1---%@",[NSThread currentThread]);
    }];
    [queue addOperation:operation];
    
    //  方式2:通過隊列直接加操作
    [queue addOperationWithBlock:^{
        NSLog(@"任務(wù)2---%@",[NSThread currentThread]);
    }];
}

補充(暫停、恢復和取消)

- (void)viewDidLoad {
    
    self.queue = [[NSOperationQueue alloc] init];
    //  任務(wù)暫停后可以恢復執(zhí)行
    if (self.queue.isSuspended) {
        self.queue.suspended = NO;
    }
    //  任務(wù)取消后不可在恢復執(zhí)行
    [self.queue cancelAllOperations];
}
3.4 設(shè)置操作依賴

通過調(diào)用操作[operation addDependency:]方法,可實現(xiàn)不同操作按指定的順序執(zhí)行

- (void)viewDidLoad {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"操作1---");
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"操作2---");
    }];
    //  operation1依賴operation2,operation2執(zhí)行完才能執(zhí)行operation1
    [operation1 addDependency:operation2];
    [queue addOperation:operation1];
    [queue addOperation:operation2];
}

打印

2016-08-02 11:02:19.161 demo[3839:3930104] 操作2---
2016-08-02 11:02:19.162 demo[3839:3930104] 操作1---

??有一種需求:前兩個異步任務(wù)都執(zhí)行完之后才開始執(zhí)行第三個
任務(wù)

- (void)viewDidLoad {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"操作1---");
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"操作2---");
    }];
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"操作3---");
    }];

    [operation3 addDependency:operation1];
    [operation3 addDependency:operation2];
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];
}

打印

2016-08-02 11:05:21.480 demo[4099:3932866] 操作2---
2016-08-02 11:05:21.480 demo[4099:3932865] 操作1---
2016-08-02 11:05:21.482 demo[4099:3932865] 操作3---
4 總結(jié)

以上主要涉及到開發(fā)中常用的一些內(nèi)容,另外至于GCD和NSOperation線程間的通信,其實常用到的是異步操作后回到主線程,只要將需要回到主線程的任務(wù)添加到主隊列即可

最后編輯于
?著作權(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)容

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